#ifndef ECODE_AUTOCOMPLETEPLUGIN_HPP #define ECODE_AUTOCOMPLETEPLUGIN_HPP #include "../lsp/lspprotocol.hpp" #include "../pluginmanager.hpp" #include #include #include #include #include #include #include using namespace EE; using namespace EE::System; using namespace EE::UI; namespace ecode { class AutoCompletePlugin : public UICodeEditorPlugin { public: class Suggestion { public: LSPCompletionItemKind kind{ LSPCompletionItemKind::Text }; std::string text; std::string detail; std::string sortText; TextRange range; double score{ 0 }; void setScore( const double& score ) const { const_cast( this )->score = score; } Suggestion( const std::string& text ) : text( text ), sortText( text ) {} Suggestion( const LSPCompletionItemKind& kind, const std::string& text, const std::string& detail, const std::string& sortText, const TextRange& range = {} ) : kind( kind ), text( text ), detail( detail ), sortText( sortText.empty() ? text : sortText ), range( range ){}; bool operator<( const Suggestion& other ) const { return getCmpStr() < other.getCmpStr(); } bool operator==( const Suggestion& other ) const { return text == other.text; } protected: const std::string* getCmpStr() const { return !sortText.empty() ? &sortText : &text; } }; typedef std::vector SymbolsList; static PluginDefinition Definition() { return { "autocomplete", "Auto Complete", "Auto complete shows the completion popup as you type, so you can fill " "in long words by typing only a few characters.", AutoCompletePlugin::New, { 0, 2, 0 } }; } static UICodeEditorPlugin* New( PluginManager* pluginManager ); virtual ~AutoCompletePlugin(); std::string getId() { return Definition().id; } std::string getTitle() { return Definition().name; } std::string getDescription() { return Definition().description; } bool isReady() const { return true; } void onRegister( UICodeEditor* ); void onUnregister( UICodeEditor* ); bool onKeyDown( UICodeEditor*, const KeyEvent& ); bool onTextInput( UICodeEditor*, const TextInputEvent& ); void update( UICodeEditor* ); void postDraw( UICodeEditor*, const Vector2f& startScroll, const Float& lineHeight, const TextPosition& cursor ); bool onMouseDown( UICodeEditor*, const Vector2i&, const Uint32& ); bool onMouseUp( UICodeEditor*, const Vector2i&, const Uint32& ); bool onMouseDoubleClick( UICodeEditor*, const Vector2i&, const Uint32& ); bool onMouseMove( UICodeEditor*, const Vector2i&, const Uint32& ); const Rectf& getBoxPadding() const; void setBoxPadding( const Rectf& boxPadding ); const Int32& getSuggestionsMaxVisible() const; void setSuggestionsMaxVisible( const Uint32& suggestionsMaxVisible ); const Time& getUpdateFreq() const; void setUpdateFreq( const Time& updateFreq ); const std::string& getSymbolPattern() const; void setSymbolPattern( const std::string& symbolPattern ); bool isDirty() const; void setDirty( bool dirty ); protected: PluginManager* mManager{ nullptr }; std::string mSymbolPattern; Rectf mBoxPadding; std::shared_ptr mPool; Clock mClock; Mutex mLangSymbolsMutex; Mutex mSuggestionsMutex; Mutex mDocMutex; Time mUpdateFreq{ Seconds( 5 ) }; std::unordered_map> mEditors; std::set mDocs; std::unordered_map mEditorDocs; bool mDirty{ false }; bool mClosing{ false }; bool mReplacing{ false }; bool mSignatureHelpVisible{ false }; struct DocCache { Uint64 changeId{ static_cast( -1 ) }; SymbolsList symbols; }; std::unordered_map mDocCache; std::unordered_map mLangCache; SymbolsList mLangDirty; std::vector mSuggestions; Mutex mSuggestionsEditorMutex; Mutex mSignatureHelpEditorMutex; UICodeEditor* mSuggestionsEditor{ nullptr }; UICodeEditor* mSignatureHelpEditor{ nullptr }; Int32 mSuggestionIndex{ 0 }; Int32 mSuggestionsMaxVisible{ 8 }; Int32 mSuggestionsStartIndex{ 0 }; std::map mCapabilities; Mutex mCapabilitiesMutex; LSPSignatureHelp mSignatureHelp; TextPosition mSignatureHelpPosition; Int32 mSignatureHelpSelected{ -1 }; Mutex mHandlesMutex; std::map> mHandles; std::map> mDocsUpdating; Mutex mDocsUpdatingMutex; Float mRowHeight{ 0 }; Rectf mBoxRect; AutoCompletePlugin( PluginManager* pluginManager ); void resetSuggestions( UICodeEditor* editor ); void updateSuggestions( const std::string& symbol, UICodeEditor* editor ); SymbolsList getDocumentSymbols( TextDocument* ); void updateDocCache( TextDocument* doc ); std::string getPartialSymbol( TextDocument* doc ); void runUpdateSuggestions( const std::string& symbol, const SymbolsList& symbols, UICodeEditor* editor ); void updateLangCache( const std::string& langName ); void pickSuggestion( UICodeEditor* editor ); PluginRequestHandle processResponse( const PluginMessage& msg ); bool tryRequestCapabilities( UICodeEditor* editor ); void requestCodeCompletion( UICodeEditor* editor ); void requestSignatureHelp( UICodeEditor* editor ); PluginRequestHandle processCodeCompletion( const LSPCompletionList& completion ); PluginRequestHandle processSignatureHelp( const LSPSignatureHelp& signatureHelp ); void resetSignatureHelp(); void drawSignatureHelp( UICodeEditor* editor, const Vector2f& startScroll, const Float& lineHeight, bool drawUp ); }; } // namespace ecode #endif // ECODE_AUTOCOMPLETEPLUGIN_HPP