From 473d4b48c92ecb6617c051bab148169a756f75b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 31 Mar 2025 22:40:15 -0300 Subject: [PATCH] Allow to configure the AI Assistant Chat UI keybindings. Allow to prefer the LSP formatter over the command line formatter in the formatter plugin, changed that option as the default for the cases where we use clangd (which fallbacks to clang-format but does diff the file). --- bin/assets/plugins/formatters.json | 6 ++-- include/eepp/ui/doc/textdocument.hpp | 2 +- .../plugins/aiassistant/aiassistantplugin.cpp | 34 ++++++++++++++++--- .../ecode/plugins/aiassistant/chatui.cpp | 11 ++++-- .../plugins/formatter/formatterplugin.cpp | 3 +- .../plugins/formatter/formatterplugin.hpp | 3 +- src/tools/ecode/plugins/plugin.hpp | 2 ++ 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/bin/assets/plugins/formatters.json b/bin/assets/plugins/formatters.json index 35d64f5c8..221e79b83 100644 --- a/bin/assets/plugins/formatters.json +++ b/bin/assets/plugins/formatters.json @@ -16,7 +16,8 @@ "language": ["c", "cpp", "objective-c", "java"], "file_patterns": ["%.inl$", "%.cpp$", "%.hpp$", "%.cc$", "%.cxx$", "%.c++$", "%.hh$", "%.hxx$", "%.h++$", "%.objcpp$", "%.m$", "%.java$"], "command": "clang-format --style=file $FILENAME", - "url": "https://clang.llvm.org/docs/ClangFormat.html" + "url": "https://clang.llvm.org/docs/ClangFormat.html", + "prefer_lsp_formatter": true }, { "language": "python", @@ -70,7 +71,8 @@ "file_patterns": ["%.zig$"], "command": "zig fmt $FILENAME", "type": "inplace", - "url": "https://ziglang.org" + "url": "https://ziglang.org", + "prefer_lsp_formatter": true }, { "language": "haskell", diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 40d939d56..623791748 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -49,7 +49,7 @@ class EE_API TextDocument { TextRange result{}; std::vector captures{}; bool isValid() const { return result.isValid(); } - bool operator==( const SearchResult& other ) { + bool operator==( const SearchResult& other ) const { return result == other.result && captures == other.captures; } }; diff --git a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp index 2690c08b1..c057dc784 100644 --- a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp +++ b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp @@ -19,7 +19,20 @@ using json = nlohmann::json; namespace ecode { static std::initializer_list AIAssistantCommandList = { - "new-ai-assistant", + + "ai-prompt", + "ai-add-chat", + "ai-chat-history", + "ai-clone-chat", + "ai-settings", + "ai-toggle-private-chat", + "ai-save-chat", + "ai-rename-chat", + "ai-show-menu", + "ai-chat-toggle-role", + "ai-refresh-local-models", + "new-ai-assistant" + }; static std::map parseLLMProviders( const nlohmann::json& j ) { @@ -192,7 +205,7 @@ void AIAssistantPlugin::load( PluginManager* pluginManager ) { FileSystem::fileGet( filePath, data ); if ( !data.empty() ) { auto j = nlohmann::json::parse( data, nullptr, false ); - if ( !j.empty() ){ + if ( !j.empty() ) { inputText = chatUI->unserialize( j ); } } @@ -285,6 +298,17 @@ void AIAssistantPlugin::loadAIAssistantConfig( const std::string& path, bool upd if ( mKeyBindings.empty() ) { mKeyBindings["new-ai-assistant"] = "mod+shift+m"; + mKeyBindings["ai-prompt"] = "mod+return"; + mKeyBindings["ai-add-chat"] = "mod+shift+return"; + mKeyBindings["ai-chat-history"] = "mod+h"; + mKeyBindings["ai-clone-chat"] = "mod+shift+c"; + mKeyBindings["ai-settings"] = "mod+shift+s"; + mKeyBindings["ai-toggle-private-chat"] = "mod+shift+p"; + mKeyBindings["ai-save-chat"] = "mod+s"; + mKeyBindings["ai-rename-chat"] = "f2"; + mKeyBindings["ai-show-menu"] = "mod+m"; + mKeyBindings["ai-chat-toggle-role"] = "mod+shift+r"; + mKeyBindings["ai-refresh-local-models"] = "mod+shift+l"; } auto& kb = j["keybindings"]; @@ -374,8 +398,10 @@ PluginRequestHandle AIAssistantPlugin::processMessage( const PluginMessage& msg switch ( msg.type ) { case ecode::PluginMessageType::UIReady: { for ( const auto& kb : mKeyBindings ) { - getPluginContext()->getMainLayout()->getKeyBindings().addKeybindString( kb.second, - kb.first ); + if ( !String::startsWith( kb.first, "ai-" ) ) { + getPluginContext()->getMainLayout()->getKeyBindings().addKeybindString( + kb.second, kb.first ); + } } if ( !mUIInit ) diff --git a/src/tools/ecode/plugins/aiassistant/chatui.cpp b/src/tools/ecode/plugins/aiassistant/chatui.cpp index e84f06789..b8abc162b 100644 --- a/src/tools/ecode/plugins/aiassistant/chatui.cpp +++ b/src/tools/ecode/plugins/aiassistant/chatui.cpp @@ -435,7 +435,12 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) : but->setTooltipText( but->getTooltipText() + " (" + kb + ")" ); }; - const auto addKb = [this]( const std::string& kb, const std::string& cmd ) { + const auto addKb = [this]( std::string kb, const std::string& cmd, bool searchDefined = true ) { + if ( searchDefined && getPlugin() ) { + const auto& find = getPlugin()->getKeybindings().find( cmd ); + if ( find != getPlugin()->getKeybindings().end() && !find->second.empty() ) + kb = find->second; + } getKeyBindings().addKeybindString( kb, cmd ); mChatInput->addKeyBindingString( kb, cmd ); }; @@ -462,8 +467,8 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) : appendShortcutToTooltip( mChatUserRole, "ai-chat-toggle-role" ); appendShortcutToTooltip( mRefreshModels, "ai-refresh-local-models" ); - addKb( "mod+keypad enter", "ai-prompt" ); - addKb( "mod+shift+keypad enter", "ai-add-chat" ); + addKb( "mod+keypad enter", "ai-prompt", false ); + addKb( "mod+shift+keypad enter", "ai-add-chat", false ); } std::optional LLMChatUI::getModel( const std::string& provider, diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index 854e5add6..5f3a89cb2 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -237,6 +237,7 @@ void FormatterPlugin::loadFormatterConfig( const std::string& path, bool updateC formatter.command = obj["command"].get(); formatter.url = obj.value( "url", "" ); + formatter.preferLSPFormatter = obj.value( "prefer_lsp_formatter", false ); if ( obj.contains( "type" ) ) { std::string typeStr( obj["type"].get() ); @@ -356,7 +357,7 @@ void FormatterPlugin::formatDoc( UICodeEditor* editor ) { Clock clock; std::shared_ptr doc = editor->getDocumentRef(); auto formatter = supportsFormatter( doc ); - if ( formatter.command.empty() ) { + if ( formatter.preferLSPFormatter || formatter.command.empty() ) { if ( supportsLSPFormatter( doc ) ) formatDocWithLSP( doc ); return; diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.hpp b/src/tools/ecode/plugins/formatter/formatterplugin.hpp index 68fb8bb84..56203d8a3 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.hpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.hpp @@ -29,12 +29,13 @@ class FormatterPlugin : public Plugin { FormatterType type{ FormatterType::Output }; std::vector languages{}; std::string url; + bool preferLSPFormatter{ false }; }; static PluginDefinition Definition() { return { "autoformatter", "Auto Formatter", "Enables the code formatter/prettifier plugin.", - FormatterPlugin::New, { 0, 2, 5 }, FormatterPlugin::NewSync }; + FormatterPlugin::New, { 0, 2, 6 }, FormatterPlugin::NewSync }; } static Plugin* New( PluginManager* pluginManager ); diff --git a/src/tools/ecode/plugins/plugin.hpp b/src/tools/ecode/plugins/plugin.hpp index 66ca452f4..a8d4e69b6 100644 --- a/src/tools/ecode/plugins/plugin.hpp +++ b/src/tools/ecode/plugins/plugin.hpp @@ -93,6 +93,8 @@ class PluginBase : public Plugin { virtual String::HashType getConfigFileHash() override { return mConfigHash; } + const std::map& getKeybindings() { return mKeyBindings; } + protected: //! Keep track of the registered editors + all the listeners registered to each editor UnorderedMap> mEditors;