Refactor in SyntaxDefinition and related classes.

Minor improvements in CPP, CSS, xit syntax highlighting.
AI Assistant / LLM Chat now can restore previous opened chats and states (last model used, panel split), can have private conversations, can clone a previous conversation, plus some visual improvements.
Fixed a bug in tab widget splitting.
This commit is contained in:
Martín Lucas Golini
2025-03-26 23:55:29 -03:00
parent 030b8dd9e6
commit 8ac5e1e2e8
25 changed files with 607 additions and 98 deletions
+1
View File
@@ -117,6 +117,7 @@ class EE_API Event {
OnModelChanged,
OnWindowToFront,
OnVisibleLinesCountChange,
OnDataChanged,
NoEvent = eeINDEX_NOT_FOUND
};
+11 -5
View File
@@ -26,6 +26,8 @@ template <typename T> static auto toSyntaxStyleTypeV( const std::vector<T>& s )
return std::vector<SyntaxStyleType>{};
}
enum class SyntaxPatternMatchType { LuaPattern, RegEx };
struct EE_API SyntaxPattern {
static UnorderedMap<SyntaxStyleType, std::string> SyntaxStyleTypeCache;
@@ -37,19 +39,23 @@ struct EE_API SyntaxPattern {
std::vector<std::string> typesNames;
std::string syntax{ "" };
DynamicSyntax dynSyntax;
bool isRegEx{ false };
SyntaxPatternMatchType matchType{ SyntaxPatternMatchType::LuaPattern };
SyntaxPattern( std::vector<std::string>&& _patterns, const std::string& _type,
const std::string& _syntax = "", bool isRegEx = false );
const std::string& _syntax = "",
SyntaxPatternMatchType matchType = SyntaxPatternMatchType::LuaPattern );
SyntaxPattern( std::vector<std::string>&& _patterns, std::vector<std::string>&& _types,
const std::string& _syntax = "", bool isRegEx = false );
const std::string& _syntax = "",
SyntaxPatternMatchType matchType = SyntaxPatternMatchType::LuaPattern );
SyntaxPattern( std::vector<std::string>&& _patterns, const std::string& _type,
DynamicSyntax&& _syntax, bool isRegEx = false );
DynamicSyntax&& _syntax,
SyntaxPatternMatchType matchType = SyntaxPatternMatchType::LuaPattern );
SyntaxPattern( std::vector<std::string>&& _patterns, std::vector<std::string>&& _types,
DynamicSyntax&& _syntax, bool isRegEx = false );
DynamicSyntax&& _syntax,
SyntaxPatternMatchType matchType = SyntaxPatternMatchType::LuaPattern );
bool hasSyntax() const { return !syntax.empty() || dynSyntax; }
};
+2 -2
View File
@@ -55,8 +55,8 @@ struct SyntaxState {
Uint8 state[MAX_SUB_SYNTAXS]{ SYNTAX_TOKENIZER_STATE_NONE, SYNTAX_TOKENIZER_STATE_NONE,
SYNTAX_TOKENIZER_STATE_NONE, SYNTAX_TOKENIZER_STATE_NONE };
// 8 bits per language (language index) - max 4 sub-languages - max 255 languages
Uint8 langStack[MAX_SUB_SYNTAXS]{ 0, 0, 0, 0 };
// 16 bits per language (language index) - max 4 sub-languages - max 65k languages
Uint16 langStack[MAX_SUB_SYNTAXS]{ 0, 0, 0, 0 };
bool operator==( const SyntaxState& other ) {
return memcmp( this, &other, sizeof( SyntaxState ) ) == 0;
@@ -161,6 +161,9 @@ class EE_API UICodeEditorSplitter {
void forEachWidgetClass( const std::string& className,
std::function<void( UIWidget* )> run ) const;
void forEachWidgetClassStoppable( const std::string& className,
std::function<bool( UIWidget* )> run ) const;
void forEachWidgetType( const UINodeType& nodeType,
std::function<void( UIWidget* )> run ) const;
+247
View File
@@ -309,6 +309,7 @@
../../include/eepp/ui/abstract/uiabstractview.hpp
../../include/eepp/ui/base.hpp
../../include/eepp/ui.hpp
../../include/eepp/ui/border.hpp
../../include/eepp/ui/models/modeleditingdelegate.hpp
../../include/eepp/ui/models/modelindex.hpp
../../include/eepp/ui/models/modelselection.hpp
@@ -348,6 +349,7 @@
../../include/eepp/ui/doc/textposition.hpp
../../include/eepp/ui/doc/textrange.hpp
../../include/eepp/ui/doc/textundostack.hpp
../../include/eepp/ui/iconmanager.hpp
../../include/eepp/ui/keyboardshortcut.hpp
../../include/eepp/ui/marginmove/scale.hpp
../../include/eepp/ui/models/csspropertiesmodel.hpp
@@ -367,6 +369,7 @@
../../include/eepp/ui/tools/uidocfindreplace.hpp
../../include/eepp/ui/tools/uiwidgetinspector.hpp
../../include/eepp/ui/uiabstractview.hpp
../../include/eepp/ui/uiapplication.hpp
../../include/eepp/ui/uibackgrounddrawable.hpp
../../include/eepp/ui/uiborderdrawable.hpp
../../include/eepp/ui/uicheckbox.hpp
@@ -393,9 +396,11 @@
../../include/eepp/ui/uilistview.hpp
../../include/eepp/ui/uiloader.hpp
../../include/eepp/ui/uimanager.hpp
../../include/eepp/ui/uimenu.hpp
../../include/eepp/ui/uimenubar.hpp
../../include/eepp/ui/uimenucheckbox.hpp
../../include/eepp/ui/uimenu.hpp
../../include/eepp/ui/uimenucheckbox.hpp
../../include/eepp/ui/uimenuitem.hpp
../../include/eepp/ui/uimenuradiobutton.hpp
../../include/eepp/ui/uimenuseparator.hpp
@@ -421,6 +426,7 @@
../../include/eepp/ui/uispinbox.hpp
../../include/eepp/ui/uisplitter.hpp
../../include/eepp/ui/uisprite.hpp
../../include/eepp/ui/uistacklayout.hpp
../../include/eepp/ui/uistackwidget.hpp
../../include/eepp/ui/uistate.hpp
../../include/eepp/ui/uistyle.hpp
@@ -441,11 +447,13 @@
../../include/eepp/ui/uitouchdraggablewidget.hpp
../../include/eepp/ui/uitreeview.hpp
../../include/eepp/ui/uiviewpager.hpp
../../include/eepp/ui/uiwidget.hpp
../../include/eepp/ui/uiwidgetcreator.hpp
../../include/eepp/ui/uiwidget.hpp
../../include/eepp/ui/uiwidgettable.hpp
../../include/eepp/ui/uiwidgettablerow.hpp
../../include/eepp/ui/uiwindow.hpp
../../include/eepp/ui/undostack.hpp
../../include/eepp/ui/widgetcommandexecuter.hpp
../../include/eepp/version.hpp
../../include/eepp/window/base.hpp
@@ -867,6 +875,7 @@
../../src/eepp/system/virtualfilesystem.cpp
../../src/eepp/system/zip.cpp
../../src/eepp/ui/abstract/filesystemmodel.hpp
../../src/eepp/ui/border.cpp
../../src/eepp/ui/doc/foldrangeservice.cpp
../../src/eepp/ui/doc/languages/adept.cpp
../../src/eepp/ui/doc/languages/adept.hpp
@@ -1131,6 +1140,7 @@
../../src/eepp/ui/doc/textrange.cpp
../../src/eepp/ui/doc/textundostack.cpp
../../src/eepp/ui/doc/documentview.cpp
../../src/eepp/ui/iconmanager.cpp
../../src/eepp/ui/keyboardshortcut.cpp
../../src/eepp/ui/models/filesystemmodel.cpp
../../src/eepp/ui/models/model.cpp
@@ -1174,9 +1184,11 @@
../../src/eepp/ui/uilistview.cpp
../../src/eepp/ui/uiloader.cpp
../../src/eepp/ui/uimanager.cpp
../../src/eepp/ui/uimenu.cpp
../../src/eepp/ui/uimenubar.cpp
../../src/eepp/ui/uimenucheckbox.cpp
../../src/eepp/ui/uimenu.cpp
../../src/eepp/ui/uimenucheckbox.cpp
../../src/eepp/ui/uimenuitem.cpp
../../src/eepp/ui/uimenuradiobutton.cpp
../../src/eepp/ui/uimenuseparator.cpp
@@ -1365,6 +1377,241 @@
../../src/modules/eterm/src/eterm/terminal/wide.hpp
../../src/modules/eterm/src/eterm/terminal/windowserrors.hpp
../../src/modules/eterm/src/eterm/ui/uiterminal.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ada.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ada.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/adept.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/adept.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/angelscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/angelscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/awkscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/awkscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/batchscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/batchscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/bazel.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/bazel.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/bend.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/bend.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/blade.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/blade.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/blueprint.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/blueprint.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/brainfuck.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/brainfuck.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/buzz.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/buzz.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/carbon.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/carbon.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/clojure.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/clojure.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/cmake.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/cmake.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/containerfile.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/containerfile.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/crystal.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/crystal.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/csharp.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/csharp.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/d.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/d.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/dart.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/dart.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/difffile.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/difffile.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/elixir.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/elixir.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/elm.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/elm.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/environmentfile.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/environmentfile.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fantom.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fantom.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fennel.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fennel.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fortran.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fortran.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fstab.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/fstab.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gdscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/gdscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/glsl.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/glsl.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/go.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/go.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/graphql.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/graphql.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/groovy.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/groovy.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/hare.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/hare.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/haskell.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/haskell.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/haxe.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/haxe.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/hlsl.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/hlsl.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/htaccess.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/htaccess.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ignorefile.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ignorefile.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jai.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jai.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/java.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/java.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jsx.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jsx.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jule.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/jule.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/julia.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/julia.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/kotlin.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/kotlin.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/latex.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/latex.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/lobster.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/lobster.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/meson.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/meson.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/moonscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/moonscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/nelua.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/nelua.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/nim.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/nim.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/objeck.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/objeck.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/objective-c.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/objective-c.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ocaml.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ocaml.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/odin.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/odin.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/openscad.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/openscad.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pascal.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pascal.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/perl.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/perl.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/php.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/php.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pico-8.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pico-8.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/po.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/po.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pony.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/pony.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/postgresql.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/postgresql.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/powershell.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/powershell.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/r.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/r.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/rave.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/rave.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ring.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ring.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ruby.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/ruby.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/rust.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/rust.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/sass.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/sass.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/scala.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/scala.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/shellscript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/shellscript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/smallbasic.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/solidity.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/solidity.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/sql.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/sql.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/svelte.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/swift.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/swift.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/tcl.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/tcl.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/teal.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/teal.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/toml.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/toml.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/typescript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/typescript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/v.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/v.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/v1.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/v1.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vala.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vala.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vb.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vb.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/verilog.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/verilog.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vue.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/vue.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/wren.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/wren.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/x86assembly.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/x86assembly.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/xit.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/xit.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/xtend.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/xtend.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/yaml.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/yaml.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/yuescript.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/yuescript.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/zig.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languages/zig.hpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.cpp
../../src/modules/languages-syntax-highlighting/src/eepp/ui/doc/languagessyntaxhighlighting.hpp
../../src/modules/maps/include/eepp/maps/base.hpp
../../src/modules/maps/include/eepp/maps/gameobject.hpp
../../src/modules/maps/include/eepp/maps/gameobjectobject.hpp
../../src/modules/maps/include/eepp/maps/gameobjectpolygon.hpp
../../src/modules/maps/include/eepp/maps/gameobjectpolyline.hpp
../../src/modules/maps/include/eepp/maps/gameobjectsprite.hpp
../../src/modules/maps/include/eepp/maps/gameobjecttextureregion.hpp
../../src/modules/maps/include/eepp/maps/gameobjecttextureregionex.hpp
../../src/modules/maps/include/eepp/maps/gameobjectvirtual.hpp
../../src/modules/maps/include/eepp/maps/mapeditor/mapeditor.hpp
../../src/modules/maps/include/eepp/maps/maphelper.hpp
../../src/modules/maps/include/eepp/maps/maplayer.hpp
../../src/modules/maps/include/eepp/maps/maplight.hpp
../../src/modules/maps/include/eepp/maps/maplightmanager.hpp
../../src/modules/maps/include/eepp/maps/mapobjectlayer.hpp
../../src/modules/maps/include/eepp/maps/maps.hpp
../../src/modules/maps/include/eepp/maps/tilemap.hpp
../../src/modules/maps/include/eepp/maps/tilemaplayer.hpp
../../src/modules/maps/src/eepp/maps/gameobject.cpp
../../src/modules/maps/src/eepp/maps/gameobjectobject.cpp
../../src/modules/maps/src/eepp/maps/gameobjectpolygon.cpp
../../src/modules/maps/src/eepp/maps/gameobjectpolyline.cpp
../../src/modules/maps/src/eepp/maps/gameobjectsprite.cpp
../../src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp
../../src/modules/maps/src/eepp/maps/gameobjecttextureregionex.cpp
../../src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/maplayerproperties.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/maplayerproperties.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/mapobjectproperties.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/mapobjectproperties.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/tilemapproperties.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/tilemapproperties.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/uigotypenew.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/uigotypenew.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimap.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimap.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimaplayernew.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimaplayernew.hpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimapnew.cpp
../../src/modules/maps/src/eepp/maps/mapeditor/uimapnew.hpp
../../src/modules/maps/src/eepp/maps/maplayer.cpp
../../src/modules/maps/src/eepp/maps/maplight.cpp
../../src/modules/maps/src/eepp/maps/maplightmanager.cpp
../../src/modules/maps/src/eepp/maps/mapobjectlayer.cpp
../../src/modules/maps/src/eepp/maps/tilemap.cpp
../../src/modules/maps/src/eepp/maps/tilemaplayer.cpp
../../src/modules/physics/include/eepp/physics/arbiter.hpp
../../src/modules/physics/include/eepp/physics/area.hpp
../../src/modules/physics/include/eepp/physics/base.hpp
+4 -1
View File
@@ -441,7 +441,10 @@ Node* Node::getNextNodeLoop() const {
}
Node* Node::setData( const UintPtr& data ) {
mData = data;
if ( data != mData ) {
mData = data;
sendCommonEvent( Event::OnDataChanged );
}
return this;
}
+2
View File
@@ -34,6 +34,8 @@ void addCPP() {
{ { "[%+%-=/%*%^%%<>!~|&]" }, "operator" },
{ { "[%a_][%w_]*%f[(]" }, "function" },
{ { "std%:%:[%w_]*" }, "keyword2" },
{ { "(%[)(%[)(%a[%w_]+)(%])(%])" },
{ "normal", "keyword", "keyword3", "keyword2", "keyword3", "keyword" } },
{ { "[%a_][%w_]*" }, "symbol" },
},
+1
View File
@@ -21,6 +21,7 @@ void addCSS() {
{ { "#[%a%_%-][%w%_%-]*" }, "keyword2" },
{ { "%-%-%a[%w%-%_]*" }, "keyword2" },
{ { "-?%d+[%d%.]*p[xt]" }, "number" },
{ { "-?%d+[%d%.]*dp" }, "number" },
{ { "-?%d+[%d%.]*deg" }, "number" },
{ { "-?%d+[%d%.]*" }, "number" },
{ { "@[%a][%w%_%-]*" }, "keyword2" },
+8 -8
View File
@@ -259,44 +259,44 @@ const String::HashType& SyntaxDefinition::getLanguageId() const {
}
SyntaxPattern::SyntaxPattern( std::vector<std::string>&& _patterns, const std::string& _type,
const std::string& _syntax, bool isRegEx ) :
const std::string& _syntax, SyntaxPatternMatchType matchType ) :
patterns( std::move( _patterns ) ),
types( toSyntaxStyleTypeV( std::vector<std::string>{ _type } ) ),
typesNames( { _type } ),
syntax( _syntax ),
isRegEx( isRegEx ) {
matchType( matchType ) {
updateCache<SyntaxStyleType>( *this );
}
SyntaxPattern::SyntaxPattern( std::vector<std::string>&& _patterns,
std::vector<std::string>&& _types, const std::string& _syntax,
bool isRegEx ) :
SyntaxPatternMatchType matchType ) :
patterns( std::move( _patterns ) ),
types( toSyntaxStyleTypeV( _types ) ),
typesNames( std::move( _types ) ),
syntax( _syntax ),
isRegEx( isRegEx ) {
matchType( matchType ) {
updateCache<SyntaxStyleType>( *this );
}
SyntaxPattern::SyntaxPattern( std::vector<std::string>&& _patterns, const std::string& _type,
DynamicSyntax&& _syntax, bool isRegEx ) :
DynamicSyntax&& _syntax, SyntaxPatternMatchType matchType ) :
patterns( std::move( _patterns ) ),
types( toSyntaxStyleTypeV( std::vector<std::string>{ _type } ) ),
typesNames( { _type } ),
dynSyntax( std::move( _syntax ) ),
isRegEx( isRegEx ) {
matchType( matchType ) {
updateCache<SyntaxStyleType>( *this );
}
SyntaxPattern::SyntaxPattern( std::vector<std::string>&& _patterns,
std::vector<std::string>&& _types, DynamicSyntax&& _syntax,
bool isRegEx ) :
SyntaxPatternMatchType matchType ) :
patterns( std::move( _patterns ) ),
types( toSyntaxStyleTypeV( _types ) ),
typesNames( std::move( _types ) ),
dynSyntax( std::move( _syntax ) ),
isRegEx( isRegEx ) {
matchType( matchType ) {
updateCache<SyntaxStyleType>( *this );
}
+10 -8
View File
@@ -81,7 +81,7 @@ static json toJson( const SyntaxDefinition& def ) {
j["patterns"] = json::array();
for ( const auto& ptrn : def.getPatterns() ) {
json pattern;
auto ptrnType = ptrn.isRegEx ? "regex" : "pattern";
auto ptrnType = ptrn.matchType == SyntaxPatternMatchType::RegEx ? "regex" : "pattern";
if ( ptrn.patterns.size() == 1 ) {
pattern[ptrnType] = ptrn.patterns[0];
} else {
@@ -206,12 +206,13 @@ namespace EE { namespace UI { namespace Doc { namespace Language {
buf += "{\n";
for ( const auto& pattern : def.getPatterns() ) {
buf += "{ " + join( pattern.patterns ) + ", " +
join( pattern.typesNames, true, true, pattern.isRegEx ) +
join( pattern.typesNames, true, true,
pattern.matchType == SyntaxPatternMatchType::RegEx ) +
str( pattern.syntax, ", ", "", false );
if ( pattern.isRegEx && pattern.syntax.empty() )
buf += ", \"\", true";
else if ( pattern.isRegEx )
buf += ", true";
if ( pattern.matchType == SyntaxPatternMatchType::RegEx && pattern.syntax.empty() )
buf += ", \"\", SyntaxPatternMatchType::RegEx";
else if ( pattern.matchType == SyntaxPatternMatchType::RegEx )
buf += ", SyntaxPatternMatchType::RegEx";
buf += " },\n";
}
buf += "\n},\n";
@@ -400,8 +401,9 @@ static SyntaxDefinition loadLanguage( const nlohmann::json& json ) {
ptrns.emplace_back( pattern["regex"] );
}
}
def.addPattern(
SyntaxPattern( std::move( ptrns ), std::move( type ), syntax, isRegEx ) );
def.addPattern( SyntaxPattern( std::move( ptrns ), std::move( type ), syntax,
isRegEx ? SyntaxPatternMatchType::RegEx
: SyntaxPatternMatchType::LuaPattern ) );
}
}
if ( json.contains( "symbols" ) ) {
+11 -8
View File
@@ -105,13 +105,15 @@ struct NonEscapedMatch {
};
static NonEscapedMatch findNonEscaped( const std::string& text, const std::string& pattern,
int offset, const std::string& escapeStr, bool isRegEx ) {
int offset, const std::string& escapeStr,
SyntaxPatternMatchType matchType ) {
eeASSERT( !pattern.empty() );
if ( pattern.empty() )
return {};
std::variant<RegEx, LuaPattern> wordsVar =
isRegEx ? std::variant<RegEx, LuaPattern>( RegEx( pattern ) )
: std::variant<RegEx, LuaPattern>( LuaPattern( pattern ) );
matchType == SyntaxPatternMatchType::RegEx
? std::variant<RegEx, LuaPattern>( RegEx( pattern ) )
: std::variant<RegEx, LuaPattern>( LuaPattern( pattern ) );
PatternMatcher& words =
std::visit( []( auto& patternType ) -> PatternMatcher& { return patternType; }, wordsVar );
int start, end;
@@ -272,7 +274,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
curState.currentSyntax->getPatterns()[curState.currentPatternIdx - 1];
auto range = findNonEscaped( text, pattern.patterns[1], i,
pattern.patterns.size() >= 3 ? pattern.patterns[2] : "",
pattern.isRegEx )
pattern.matchType )
.range;
bool skip = false;
@@ -283,7 +285,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
curState.subsyntaxInfo->patterns.size() >= 3
? curState.subsyntaxInfo->patterns[2]
: "",
pattern.isRegEx );
pattern.matchType );
if ( rangeSubsyntax.range.first != -1 &&
( range.first == -1 || rangeSubsyntax.range.first < range.first ) ) {
@@ -320,7 +322,7 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
text, "^" + curState.subsyntaxInfo->patterns[1], i,
curState.subsyntaxInfo->patterns.size() >= 3 ? curState.subsyntaxInfo->patterns[2]
: "",
curState.subsyntaxInfo->isRegEx );
curState.subsyntaxInfo->matchType );
if ( rangeSubsyntax.range.first != -1 ) {
if ( !skipSubSyntaxSeparator ) {
@@ -342,8 +344,9 @@ _tokenize( const SyntaxDefinition& syntax, const std::string& text, const Syntax
patternStr =
pattern.patterns[0][0] == '^' ? pattern.patterns[0] : "^" + pattern.patterns[0];
std::variant<RegEx, LuaPattern> wordsVar =
pattern.isRegEx ? std::variant<RegEx, LuaPattern>( RegEx( patternStr ) )
: std::variant<RegEx, LuaPattern>( LuaPattern( patternStr ) );
pattern.matchType == SyntaxPatternMatchType::RegEx
? std::variant<RegEx, LuaPattern>( RegEx( patternStr ) )
: std::variant<RegEx, LuaPattern>( LuaPattern( patternStr ) );
PatternMatcher& words = std::visit(
[]( auto& patternType ) -> PatternMatcher& { return patternType; }, wordsVar );
if ( !words.isValid() ) // Skip invalid patterns
+2
View File
@@ -99,6 +99,8 @@ UIIconTheme* IconManager::init( const std::string& iconThemeName, FontTrueType*
{ "code-ai", 0xF56F },
{ "robot-2", 0xF3D9 },
{ "chat-history", 0xEB61 },
{ "chat-private", 0xEB69 },
{ "loader-2", 0xEEC2 },
};
for ( const auto& icon : icons )
@@ -786,6 +786,22 @@ void UICodeEditorSplitter::forEachWidgetClass( const std::string& className,
}
}
void UICodeEditorSplitter::forEachWidgetClassStoppable(
const std::string& className, std::function<bool( UIWidget* )> run ) const {
Node* node;
UIWidget* widget;
for ( auto tabWidget : mTabWidgets ) {
for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) {
node = tabWidget->getTab( i )->getOwnedWidget();
if ( node && node->isWidget() ) {
widget = node->asType<UIWidget>();
if ( widget->hasClass( className ) && run( widget ) )
return;
}
}
}
}
void UICodeEditorSplitter::forEachWidgetType( const UINodeType& nodeType,
std::function<void( UIWidget* )> run ) const {
Node* node;
+2
View File
@@ -1036,6 +1036,8 @@ Uint32 UITabWidget::onMessage( const NodeMessage* msg ) {
return 1;
}
} else if ( dir && tab->getTabWidget()->allowDragAndDropTabs() ) {
if ( tab->getTabWidget() == this && tab->getTabWidget()->getTabCount() <= 1 )
return 0;
tab->getTabWidget()->removeTab( tab, false, false, false );
auto tabWidget = mSplitFn( *dir, this );
tabWidget->add( tab );
@@ -30,20 +30,20 @@ void addSvelte() {
{ { "<!%-%-", "%-%->" }, "comment" },
{ { "\"", "\"", "\\" }, "string" },
{ { "'", "'", "\\" }, "string" },
{ { "{@html[^}]*}" }, "keyword", "", true },
{ { "{@debug[^}]*}" }, "keyword", "", true },
{ { "{@html[^}]*}" }, "keyword", "", SyntaxPatternMatchType::RegEx },
{ { "{@debug[^}]*}" }, "keyword", "", SyntaxPatternMatchType::RegEx },
{ { "{(:else|:then|:catch)}" },
std::vector<std::string>{ "keyword", "keyword2" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "{(/if|/each|/await|/key)}" },
std::vector<std::string>{ "keyword", "keyword2" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "{(#if|#each|#await|#key)", "}", "\\" },
std::vector<std::string>{ "keyword", "keyword2", "normal" },
"JavaScript",
true },
SyntaxPatternMatchType::RegEx },
{ { "{", "}", "\\" }, "keyword", "JavaScript" },
{ { "([%a_][%w_-]*)(:)([%a_][%w_-]*)(=)" },
{ "keyword", "keyword2", "normal", "keyword", "operator" } },
@@ -4,12 +4,20 @@
namespace EE { namespace UI { namespace Doc { namespace Language {
void addXit() {
auto dynSyntax = []( const SyntaxPattern&, const std::string_view& match ) -> std::string {
std::string lang = String::toLower( std::string{ match.substr( 3 ) } );
String::trimInPlace( lang );
if ( !lang.empty() && lang[lang.size() - 1] == '\n' )
lang.pop_back();
return SyntaxDefinitionManager::instance()->findFromString( lang ).getLanguageName();
};
SyntaxDefinitionManager::instance()->add(
{ "[x]it!",
{ "%.xit$" },
{
{ { "```[%w%s+-#]+", "```" }, "function", dynSyntax },
{ { "%f[^%s%(]%-%>%s%d%d%d%d%-%d%d%-%d%d%f[\n%s%!%?%)]" }, "number" },
{ { "%f[^%s%(]%-%>%s%d%d%d%d%/%d%d%/%d%d%f[\n%s%!%?%)]" }, "number" },
{ { "%f[^%s%(]%-%>%s%d%d%d%d%-[wWqQ]?%d%d?%f[\n%s%!%?%)]" }, "number" },
@@ -45,7 +45,7 @@ void addYueScript() {
"local|class|if|else|elseif|repeat|continue|break|using|import)\\s+)" },
{ "normal", "normal", "keyword" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "([%a_][%w_]*)(%s+not%s+in)" }, { "normal", "normal", "keyword" } },
{ { "([%a_][%w_]*)(%s+%f[%[%$%a_])" }, { "normal", "function", "normal" } },
{ { "(|>%s*)([%a_][%.%w_]*%.%s*)([%a_][%w_]*)" },
@@ -55,16 +55,16 @@ void addYueScript() {
"\\da-fA-F])*)?)" },
{ "normal", "function", "number" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "([a-zA-Z_]\\w*\\s+)(\\-?\\.\\d(?:_?\\d)*(?:[eE][\\+\\-]?\\d(?:_?\\d)*)?)" },
{ "normal", "function", "number" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "([a-zA-Z_]\\w*\\s+)(\\-?(?:\\d(?:_?\\d)*)(?:(?:\\.\\d(?:_?\\d)*(?:[eE][\\+\\-]?"
"\\d(?:_?\\d)*)?)|[eE][\\+\\-]?\\d(?:_?\\d)*)?)" },
{ "normal", "function", "number" },
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "([%a_][%w_]*)(%??%s*!=)" }, { "normal", "normal", "operator" } },
{ { "([%a_][%w_]*)(%??%s*!)" }, { "normal", "function", "operator" } },
{ { "(::)([%a_][%w_]*)(::)" }, { "normal", "operator", "keyword2", "operator" } },
@@ -73,13 +73,16 @@ void addYueScript() {
{ { "\\-?0x[\\da-fA-F](?:_?[\\da-fA-F])*(?:\\.[\\da-fA-F](?:_?[\\da-fA-F])*)?" },
"number",
"",
true },
{ { "\\-?\\.\\d(?:_?\\d)*(?:[eE][\\+\\-]?\\d(?:_?\\d)*)?" }, "number", "", true },
SyntaxPatternMatchType::RegEx },
{ { "\\-?\\.\\d(?:_?\\d)*(?:[eE][\\+\\-]?\\d(?:_?\\d)*)?" },
"number",
"",
SyntaxPatternMatchType::RegEx },
{ { "\\-?(?:\\d(?:_?\\d)*)(?:(?:\\.\\d(?:_?\\d)*(?:[eE][\\+\\-]?\\d(?:_?\\d)*)?)|[eE]"
"[\\+\\-]?\\d(?:_?\\d)*)?" },
"number",
"",
true },
SyntaxPatternMatchType::RegEx },
{ { "@@?[%w_]*" }, "keyword2" },
{ { "$[%w_]+" }, "keyword2" },
{ { "[%a_][%w_]*" }, "symbol" },
+4 -1
View File
@@ -223,11 +223,12 @@ void AppConfig::load( const std::string& confPath, std::string& keybindingsPath,
"git" == creator.first || "debugger" == creator.first ||
"aiassistant" == creator.first );
}
pluginManager->setPluginsEnabled( pluginsEnabled, sync );
languagesExtensions.priorities = ini.getKeyMap( "languages_extensions" );
iniInfo = FileInfo( ini.path() );
pluginManager->setPluginsEnabled( pluginsEnabled, sync );
}
void AppConfig::save( const std::vector<std::string>& recentFiles,
@@ -372,6 +373,8 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
for ( const auto& langExt : languagesExtensions.priorities )
ini.setValue( "languages_extensions", langExt.first, langExt.second );
pluginManager->forEachPlugin( [this]( Plugin* plugin ) { plugin->onSaveState( &iniState ); } );
ini.writeFile();
iniState.writeFile();
}
@@ -167,11 +167,45 @@ void AIAssistantPlugin::load( PluginManager* pluginManager ) {
TabWidgetCbs config;
config.onLoad = [this]( const nlohmann::json& j ) {
return TabWidgetData{ LLMChatUI::New( mManager ), getPluginContext()->findIcon( "code-ai" ),
LLMChatUI* chatUI = LLMChatUI::New( mManager );
if ( j.contains( "uuid" ) && j.contains( "summary" ) ) {
auto uuid = j.value( "uuid", "" );
auto filePath = chatUI->getNewFilePath( uuid, j.value( "summary", "" ) );
if ( filePath.empty() || !FileSystem::fileExists( filePath ) ) {
auto conversationsPath = getConversationsPath();
FileSystem::dirAddSlashAtEnd( conversationsPath );
auto conversations = FileSystem::filesGetInPath( conversationsPath );
auto foundIt = std::find_if( conversations.begin(), conversations.end(),
[&uuid]( const std::string& path ) {
return String::startsWith( path, uuid );
} );
if ( foundIt != conversations.end() )
filePath = conversationsPath + *foundIt;
}
if ( !filePath.empty() ) {
std::string data;
FileSystem::fileGet( filePath, data );
auto j = nlohmann::json::parse( data, nullptr, false );
chatUI->unserialize( j );
}
chatUI->on( Event::OnDataChanged, [chatUI]( auto ) { chatUI->updateTabTitle(); } );
}
return TabWidgetData{ chatUI, getPluginContext()->findIcon( "code-ai" ),
i18n( "ai_assistant", "AI Assistant" ) };
};
config.onSave = []( UIWidget* widget ) {
LLMChatUI* chatUI = static_cast<LLMChatUI*>( widget );
nlohmann::json j;
if ( chatUI->hasChat() ) {
j["uuid"] = chatUI->getUUID().toString();
j["summary"] = chatUI->getSummary();
}
return j;
};
@@ -365,7 +399,7 @@ void AIAssistantPlugin::initUI() {
mStatusButton->setClass( "status_but" );
mStatusButton->setIcon( iconDrawable( "code-ai", 14 ) );
mStatusButton->setTooltipText( i18n( "ai_assistant", "AI Assistant" ) );
mStatusButton->on( Event::MouseClick, [this]( const Event* event ) { newAIAssistant(); } );
mStatusButton->on( Event::MouseClick, [this]( const Event* ) { newAIAssistant(); } );
}
}
@@ -408,4 +442,32 @@ std::optional<std::string> AIAssistantPlugin::getApiKeyFromProvider( const std::
return {};
}
void AIAssistantPlugin::onSaveState( IniFile* state ) {
std::vector<LLMChatUI*> chats;
LLMChatUI* mainChat{ nullptr };
getPluginContext()->getSplitter()->forEachWidgetClass(
"llm_chatui", [&chats, &mainChat]( UIWidget* widget ) {
LLMChatUI* chat = static_cast<LLMChatUI*>( widget );
chats.emplace_back( chat );
if ( widget->isVisible() && mainChat == nullptr )
mainChat = chat;
} );
if ( mainChat == nullptr && !chats.empty() )
mainChat = chats[chats.size() - 1];
if ( mainChat == nullptr )
return;
auto partition = mainChat->getSplitter()->getSplitPartition();
auto modelProvider = mainChat->getCurModel().provider;
auto modelName = mainChat->getCurModel().name;
const std::string keyname = "aiassistant";
state->setValue( keyname, "split_partition", partition.toString() );
state->setValue( keyname, "default_provider", modelProvider );
state->setValue( keyname, "default_model", modelName );
}
} // namespace ecode
@@ -38,6 +38,8 @@ class AIAssistantPlugin : public PluginBase {
LLMChatUI* newAIAssistant();
void onSaveState( IniFile* state ) override;
protected:
LLMProviders mProviders;
bool mUIInit{ false };
+147 -41
View File
@@ -1,6 +1,8 @@
#include "chatui.hpp"
#include "../../appconfig.hpp"
#include "../../notificationcenter.hpp"
#include "aiassistantplugin.hpp"
#include "chathistory.hpp"
#include "chatui.hpp"
#include "eepp/ui/uiloader.hpp"
#include <eepp/system/filesystem.hpp>
@@ -66,9 +68,6 @@ static const char* DEFAULT_LAYOUT = R"xml(
border: 0;
background-color: var(--tab-back);
}
.llm_chatui #llm_settings_but {
tint: var(--floating-icon);
}
.llm_conversation {
margin-bottom: 8dp;
}
@@ -103,11 +102,13 @@ CodeEditor.llm_chat_input {
border-radius: 8dp;
padding-bottom: 38dp;
}
.llm_chatui PushButton {
.llm_chatui PushButton,
.llm_chatui SelectButton {
border-color: transparent;
text-as-fallback: true;
}
.llm_chatui PushButton:hover {
.llm_chatui PushButton:hover,
.llm_chatui SelectButton:hover {
border-color: var(--primary);
}
.llm_conversation_opt PushButton {
@@ -137,17 +138,19 @@ DropDownList.role_ui {
<RelativeLayout lw="mp" class="llm_controls">
<CodeEditor class="llm_chat_input" lw="mp" lh="mp" />
<hbox lw="mp" lh="wc" layout_gravity="bottom|left" layout_margin="8dp" clip="false">
<PushButton id="llm_user" class="llm_button" text="@string(user, User)" min-width="60dp" layout-margin-right="8dp" />
<PushButton class="llm_button" text="@string(attach, Attach)" icon="icon(attach, 14dp)" min-width="32dp" />
<PushButton id="llm_chat_history" class="llm_button" text="@string(chat_history, Chat History)" icon="icon(chat-history, 14dp)" min-width="32dp" />
<PushButton id="llm_settings_but" text="@string(settings, Settings)" icon="icon(settings, 14dp)" tooltip="@string(settings, Settings)" margin-right="8dp" />
<PushButton id="llm_user" class="llm_button" text="@string(user, User)" min-width="60dp" margin-right="8dp" />
<!-- <PushButton class="llm_button" text="@string(attach, Attach)" tooltip="@string(attach, Attach)" icon="icon(attach, 14dp)" min-width="32dp" /> -->
<PushButton id="llm_chat_history" class="llm_button" text="@string(chat_history, Chat History)" tooltip="@string(chat_history, Chat History)" icon="icon(chat-history, 14dp)" min-width="32dp" />
<PushButton id="llm_settings_but" class="llm_button" text="@string(settings, Settings)" tooltip="@string(settings, Settings)" icon="icon(settings, 14dp)" min-width="32dp" />
<PushButton id="llm_clone_chat" class="llm_button" text="@string(clone_current_conversation, Clone Current Conversation)" tooltip="@string(clone_current_chat, Clone Current Chat)" icon="icon(file-copy, 12dp)" min-width="32dp" />
<hbox lw="0" lw8="1" lh="mp" layout_gravity="center" padding-left="8dp" padding-right="8dp">
<DropDownList class="model_ui" lw="0" lw8="1" selected-index="0"></DropDownList>
<PushButton id="refresh_model_ui" text="@string(refresh_model_ui, Refresh)" icon="icon(refresh, 14dp)" />
</hbox>
<PushButton id="llm_add_chat" class="llm_button" text="@string(add, Add)" icon="icon(add, 15dp)" min-width="32dp" layout-margin-right="8dp" />
<PushButton id="llm_run" class="llm_button primary" text="@string(run, Run)" icon="icon(play-filled, 14dp)" />
<PushButton id="llm_stop" class="llm_button primary" text="@string(stop, Stop)" icon="icon(stop, 12dp)" visible="false" enabled="false" />
<SelectButton id="llm_private_chat" class="llm_button" tooltip="@string(private_chat, Toggle Private Chat)" icon="icon(chat-private, 14dp)" min-width="32dp" margin-right="8dp" select-on-click="true" />
<PushButton id="llm_add_chat" class="llm_button" text="@string(add, Add)" tooltip="@string(add_message, Add Message)" icon="icon(add, 15dp)" min-width="32dp" layout-margin-right="8dp" />
<PushButton id="llm_run" class="llm_button primary" text="@string(run, Run)" tooltip="@string(add_message_and_run_prompt, Add Message and Run Prompt)" icon="icon(play-filled, 14dp)" />
<PushButton id="llm_stop" class="llm_button primary" text="@string(stop, Stop)" icon="icon(stop, 12dp)" min-width="32dp" visible="false" enabled="false" />
</hbox>
</RelativeLayout>
</Splitter>
@@ -165,7 +168,9 @@ static const char* DEFAULT_CHAT_GLOBE = R"xml(
<PushButton class="move_down" text="@string(move_down, Move Down)" icon="icon(arrow-down-s, 12dp)" tooltip="@string(move_down, Move Down)" />
<PushButton class="erase_but" text="@string(remove_chat, Remove Chat)" icon="icon(chrome-close, 10dp)" tooltip="@string(remove_chat, Remove Chat)" />
</hbox>
<CodeEditor class="data_ui" lw="mp" lh="32dp" />
<CodeEditor class="data_ui" lw="mp" lh="32dp">
<Image class="thinking" icon="icon(loader-2, 24dp)" visible="false" />
</CodeEditor>
</vbox>
)xml";
@@ -173,7 +178,8 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) : UILinearLayout(), mManager( man
setClass( "llm_chatui" );
setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
getUISceneNode()->loadLayoutFromString( DEFAULT_LAYOUT, this );
mChatSplitter =
getUISceneNode()->loadLayoutFromString( DEFAULT_LAYOUT, this )->asType<UISplitter>();
mChatsList = findByClass( "llm_chats" );
mModelDDL = findByClass<UIDropDownList>( "model_ui" );
@@ -272,6 +278,27 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) : UILinearLayout(), mManager( man
}
} );
mChatPrivate = find<UISelectButton>( "llm_private_chat" );
mChatPrivate->on( Event::OnValueChange,
[this]( auto ) { mChatIsPrivate = mChatPrivate->isSelected(); } );
mChatClone = find<UIPushButton>( "llm_clone_chat" );
mChatClone->onClick( [this]( auto ) {
if ( getPlugin() == nullptr )
return;
auto chats = findAllByClass( "llm_conversation" );
if ( chats.empty() ) {
getPlugin()->getPluginContext()->getNotificationCenter()->addNotification(
i18n( "nothing_to_clone", "Nothing to Clone" ) );
return;
}
auto* chatUI = getPlugin()->newAIAssistant();
chatUI->unserialize( serialize() );
chatUI->mUUID = UUID();
chatUI->mSummary += i18n( "chat_cloned", " (cloned)" );
updateTabTitle();
} );
mChatHistory = find<UIPushButton>( "llm_chat_history" );
mChatHistory->onClick( [this]( auto ) { showChatHistory(); } );
@@ -282,32 +309,61 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) : UILinearLayout(), mManager( man
setProviders( std::move( providers ) );
mCurModel = getDefaultModel();
AppConfig& config = getPlugin()->getPluginContext()->getConfig();
auto partition = config.iniState.getValue( "aiassistant", "split_partition", "" );
if ( !partition.empty() )
mChatSplitter->setSplitPartition( StyleSheetLength::fromString( partition ) );
auto modelProvider = config.iniState.getValue( "aiassistant", "default_provider", "" );
auto modelName = config.iniState.getValue( "aiassistant", "default_model", "" );
if ( !modelProvider.empty() && !modelName.empty() ) {
auto modelOpt = getModel( modelProvider, modelName );
if ( modelOpt ) {
mCurModel = *modelOpt;
}
}
fillModelDropDownList( mModelDDL );
}
std::optional<LLMModel> LLMChatUI::getModel( const std::string& provider,
const std::string& modelName ) {
auto providerIt = mProviders.find( provider );
if ( providerIt != mProviders.end() ) {
const auto& models = providerIt->second.models;
auto modelIt =
std::find_if( models.begin(), models.end(), [&modelName]( const LLMModel& model ) {
return model.name == modelName;
} );
if ( modelIt != models.end() )
return *modelIt;
}
return {};
}
void LLMChatUI::showChatHistory() {
auto plugin = getPlugin();
if ( plugin == nullptr )
return;
UIWindow* win =
UIWindow::NewOpt( UIMessageBox::WindowBaseContainerType::VERTICAL_LINEAR_LAYOUT );
UIWindow* win = UIWindow::New();
win->setMinWindowSize( mDpSize.getWidth(), getUISceneNode()->getSize().getHeight() * 0.7f );
win->setKeyBindingCommand( "closeWindow", [win, this] {
win->closeWindow();
setFocus();
} );
win->getKeyBindings().addKeybind( { KEY_ESCAPE }, "closeWindow" );
win->setWindowFlags( UI_WIN_NO_DECORATION | UI_WIN_SHADOW |
UI_WIN_MODAL | UI_WIN_EPHEMERAL );
win->setWindowFlags( UI_WIN_SHADOW | UI_WIN_MODAL | UI_WIN_EPHEMERAL );
win->setTitle( i18n( "ai_conversations_history", "AI Conversations History" ) );
win->center();
win->setId( UUID().toString() );
UITextInput* input = UITextInput::New();
input->setParent( win->getContainer() );
input->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
input->setHint( i18n( "search_chat_ellipsis", "Search Chat..." ) );
input->setVisible( false );
UILinearLayout* layout = UILinearLayout::NewVertical();
layout->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
layout->setParent( win->getContainer() );
UILoader* loader = UILoader::New();
loader->setId( "loader" );
@@ -315,19 +371,26 @@ void LLMChatUI::showChatHistory() {
loader->setOutlineThickness( 6 );
loader->setParent( win->getContainer() );
loader->setIndeterminate( true );
loader->center();
UITextInput* input = UITextInput::New();
input->setParent( layout );
input->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
input->setHint( i18n( "search_chat_ellipsis", "Search Chat..." ) );
input->setVisible( false );
UITableView* tv = UITableView::New();
tv->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed );
tv->setLayoutWeight( 1 );
tv->setParent( win->getContainer() );
tv->setParent( layout );
tv->setVisible( false );
tv->setAutoColumnsWidth( true );
tv->setFitAllColumnsToWidget( true );
tv->setSetupCellCb( [this, tv]( UITableCell* cell ) {
tv->setSetupCellCb( [this, tv, win]( UITableCell* cell ) {
if ( cell->getCurIndex().column() != ChatHistoryModel::Remove )
return;
cell->onClick( [this, tv, cell]( const MouseEvent* event ) {
cell->onClick( [this, tv, cell, win]( const MouseEvent* ) {
ChatHistoryModel* model = static_cast<ChatHistoryModel*>( tv->getModel() );
auto summary =
model->data( model->index( cell->getCurIndex().row(), ChatHistoryModel::Summary ) )
@@ -338,6 +401,8 @@ void LLMChatUI::showChatHistory() {
"Are you sure you want to remove \"%s?\"" )
.toUtf8(),
summary ) );
msgBox->setParent( win );
msgBox->center();
msgBox->showWhenReady();
msgBox->on( Event::OnConfirm,
[model, cell]( auto ) { model->remove( cell->getCurIndex() ); } );
@@ -570,11 +635,12 @@ nlohmann::json LLMChatUI::serializeChat( const LLMModel& model ) {
}
nlohmann::json LLMChatUI::serialize() {
mTimestamp = std::chrono::system_clock::to_time_t( std::chrono::system_clock::now() );
nlohmann::json j;
j["uuid"] = mUUID.toString();
j["chat"] = serializeChat( mCurModel );
j["provider"] = mCurModel.provider;
j["timestamp"] = std::chrono::system_clock::to_time_t( std::chrono::system_clock::now() );
j["timestamp"] = mTimestamp;
j["summary"] = mSummary;
return j;
}
@@ -630,15 +696,25 @@ LLMModel LLMChatUI::getDefaultModel() {
return findModel( "openai", "gpt-4o" );
}
void LLMChatUI::saveChat() {
std::string LLMChatUI::getNewFilePath( const std::string& uuid, const std::string& summary ) const {
auto plugin = getPlugin();
if ( plugin == nullptr )
return;
if ( plugin == nullptr || mChatIsPrivate )
return "";
std::string conversationsPath = plugin->getConversationsPath();
if ( !FileSystem::fileExists( conversationsPath ) )
FileSystem::makeDir( conversationsPath, true );
std::string path( conversationsPath + mUUID.toString() + " - " + mSummary + ".json" );
FileSystem::fileWrite( path, serialize().dump( 2 ) );
return conversationsPath + uuid + " - " + summary + ".json";
}
std::string LLMChatUI::getFilePath() const {
return getNewFilePath( mUUID.toString(), mSummary );
}
void LLMChatUI::saveChat() {
auto plugin = getPlugin();
if ( plugin == nullptr || mChatIsPrivate )
return;
FileSystem::fileWrite( getFilePath(), serialize().dump( 2 ) );
}
std::string LLMChatUI::prepareApiUrl( const std::string& apiKey ) {
@@ -669,17 +745,38 @@ void LLMChatUI::doRequest() {
auto model = mCurModel;
auto* editor = chat->findByClass<UICodeEditor>( "data_ui" );
auto* thinking = editor->findByClass<UIImage>( "thinking" );
auto thinkingID = String::hash( String::format( "thinking-%p", thinking ) );
thinking->setVisible( true );
thinking->setPosition( { PixelDensity::dpToPx( 16 ), PixelDensity::dpToPx( 4 ) } );
thinking->setInterval( [thinking] { thinking->rotate( 360 / 32 ); }, Seconds( 0.125 ),
thinkingID );
std::string apiUrl( prepareApiUrl( apiKeyStr ) );
mRequest = std::make_unique<LLMChatCompletionRequest>(
apiUrl, apiKeyStr, serializeChat( model ).dump(), model.provider );
mRequest->streamedResponseCb = [this, editor]( const std::string& chunk ) {
mRequest->streamedResponseCb = [this, editor, thinking, thinkingID]( const std::string& chunk,
bool fromReasoning ) {
if ( fromReasoning )
return;
auto conversation = chunk;
editor->runOnMainThread( [this, conversation = std::move( conversation ), editor] {
editor->getDocument().textInput( String::fromUtf8( conversation ) );
editor->setCursorVisible( false );
resizeToFit( editor );
} );
editor->runOnMainThread(
[this, conversation = std::move( conversation ), editor, thinking, thinkingID] {
editor->getDocument().textInput( String::fromUtf8( conversation ) );
editor->setCursorVisible( false );
thinking->removeActionsByTag( thinkingID );
thinking->setVisible( false );
resizeToFit( editor );
} );
};
mRequest->cancelCb = [this, thinking, thinkingID]( const LLMChatCompletionRequest& ) {
thinking->removeActionsByTag( thinkingID );
thinking->setVisible( false );
removeLastChat();
};
mRequest->doneCb = [this, editor, apiUrl = std::move( apiUrl ),
apiKeyStr = std::move( apiKeyStr ), model = std::move( model )](
const LLMChatCompletionRequest&, Http::Response& response ) {
@@ -709,7 +806,8 @@ void LLMChatUI::doRequest() {
if ( editor->hasFocus() )
mChatInput->setFocus();
if ( !mSummaryRequest && mSummary.empty() && status == Http::Response::Ok ) {
if ( !mChatIsPrivate && !mSummaryRequest && mSummary.empty() &&
status == Http::Response::Ok ) {
static const std::string SummaryPrompt =
"Generate a concise 3-7 word title for this conversation, omitting "
"punctuation. Go "
@@ -869,7 +967,7 @@ void LLMChatUI::showMsg( String msg ) {
msgBox->showWhenReady();
}
AIAssistantPlugin* LLMChatUI::getPlugin() {
AIAssistantPlugin* LLMChatUI::getPlugin() const {
auto plugin = mManager->get( "aiassistant" );
if ( plugin )
return reinterpret_cast<AIAssistantPlugin*>( plugin );
@@ -903,4 +1001,12 @@ void LLMChatUI::updateTabTitle() {
tab->setText( title );
}
UISplitter* LLMChatUI::getSplitter() const {
return mChatSplitter;
}
const LLMModel& LLMChatUI::getCurModel() const {
return mCurModel;
}
} // namespace ecode
+26 -5
View File
@@ -53,17 +53,38 @@ class LLMChatUI : public UILinearLayout {
void unserialize( const nlohmann::json& payload );
UISplitter* getSplitter() const;
const LLMModel& getCurModel() const;
const UUID& getUUID() const { return mUUID; }
const std::string& getSummary() const { return mSummary; }
long getTimestamp() const { return mTimestamp; }
bool hasChat() const { return getTimestamp() && !getSummary().empty(); }
std::string getNewFilePath( const std::string& uuid, const std::string& summary ) const;
std::string getFilePath() const;
void updateTabTitle();
protected:
UUID mUUID;
std::string mSummary;
long mTimestamp;
long mTimestamp{ 0 };
PluginManager* mManager{ nullptr };
UISplitter* mChatSplitter{ nullptr };
UIWidget* mChatsList{ nullptr };
UICodeEditor* mChatInput{ nullptr };
UIPushButton* mChatUserRole{ nullptr };
UIPushButton* mChatRun{ nullptr };
UIPushButton* mChatStop{ nullptr };
UIPushButton* mChatHistory{ nullptr };
UIPushButton* mChatClone{ nullptr };
UISelectButton* mChatPrivate{ nullptr };
UIScrollView* mChatScrollView{ nullptr };
UIDropDownList* mModelDDL{ nullptr };
std::unique_ptr<LLMChatCompletionRequest> mRequest;
@@ -72,6 +93,7 @@ class LLMChatUI : public UILinearLayout {
LLMModel mCurModel;
std::unordered_map<String::HashType, LLMModel> mModelsMap;
int mPendingModelsToLoad{ 0 };
bool mChatIsPrivate{ false };
LLMModel findModel( const std::string& provider, const std::string& model );
@@ -79,7 +101,7 @@ class LLMChatUI : public UILinearLayout {
LLMChatUI( PluginManager* manager );
AIAssistantPlugin* getPlugin();
AIAssistantPlugin* getPlugin() const;
void showMsg( String msg );
@@ -119,14 +141,13 @@ class LLMChatUI : public UILinearLayout {
const LLMModel& getCheapestModelFromCurrentProvider() const;
std::optional<LLMModel> getModel( const std::string& provider, const std::string& modelName );
void saveChat();
void onInit();
void showChatHistory();
void updateTabTitle();
};
} // namespace ecode
@@ -24,6 +24,8 @@ LLMChatCompletionRequest::LLMChatCompletionRequest( const std::string& uri, cons
const Http::Request::Status& status, size_t, size_t ) {
if ( mCancel ) {
mRequest.cancel();
if ( cancelCb )
cancelCb( *this );
return false;
}
if ( status != Http::Request::ContentReceived )
@@ -47,7 +49,7 @@ LLMChatCompletionRequest::LLMChatCompletionRequest( const std::string& uri, cons
if ( delta.empty() )
return;
if ( streamedResponseCb )
streamedResponseCb( delta );
streamedResponseCb( delta, false );
mResponse += std::move( delta );
}
}
@@ -64,10 +66,14 @@ LLMChatCompletionRequest::LLMChatCompletionRequest( const std::string& uri, cons
nlohmann::json& choices = data["choices"];
for ( const auto& choice : choices ) {
if ( choice["delta"].contains( "content" ) ) {
if ( choice["delta"].contains( "reasoning_content" ) ) {
std::string delta = choice["delta"]["reasoning_content"];
if ( streamedResponseCb )
streamedResponseCb( delta, true );
} else if ( choice["delta"].contains( "content" ) ) {
std::string delta = choice["delta"]["content"];
if ( streamedResponseCb )
streamedResponseCb( delta );
streamedResponseCb( delta, false );
mResponse += std::move( delta );
}
}
@@ -76,7 +82,7 @@ LLMChatCompletionRequest::LLMChatCompletionRequest( const std::string& uri, cons
data["delta"].value( "type", "" ) == "text_delta" ) {
std::string delta = data["delta"]["text"];
if ( streamedResponseCb )
streamedResponseCb( delta );
streamedResponseCb( delta, false );
mResponse += std::move( delta );
}
} );
@@ -14,15 +14,19 @@ namespace ecode {
class LLMChatCompletionRequest {
public:
using StreamedResponseCb = std::function<void( const std::string& chunk )>;
using StreamedResponseCb = std::function<void( const std::string& chunk, bool fromReasoning )>;
using StreamedResponseDoneCb =
std::function<void( const LLMChatCompletionRequest& request, Http::Response& )>;
using StreamedResponseCancelCb = std::function<void( const LLMChatCompletionRequest& request )>;
StreamedResponseCb streamedResponseCb;
StreamedResponseDoneCb doneCb;
StreamedResponseCancelCb cancelCb;
LLMChatCompletionRequest( const std::string& uri, const std::string& auth,
const std::string& reqBody, const std::string& provider );
+6
View File
@@ -9,6 +9,10 @@ using namespace EE;
using namespace EE::UI;
using namespace EE::UI::Models;
namespace EE::System {
class IniFile;
}
namespace ecode {
class PluginManager;
@@ -53,6 +57,8 @@ class Plugin : public UICodeEditorPlugin {
void showMessage( LSPMessageType type, const std::string& message,
const std::string& title = "" );
virtual void onSaveState( IniFile* state ) {}
virtual void onSaveProject( const std::string& /*projectFolder*/,
const std::string& /*projectStatePath*/,
bool /*rewriteStateOnlyIfNeeded*/ ) {}