diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index bd8f3f279..e07817c28 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -26,6 +26,11 @@ using namespace EE::Network; namespace EE { namespace UI { namespace Doc { +struct DocumentContentChange { + TextRange range; + String text; +}; + class EE_API TextDocument { public: typedef std::function DocumentCommand; @@ -43,8 +48,8 @@ class EE_API TextDocument { class EE_API Client { public: virtual ~Client(); - virtual void onDocumentLoaded( TextDocument* ) {}; - virtual void onDocumentTextChanged() = 0; + virtual void onDocumentLoaded( TextDocument* ){}; + virtual void onDocumentTextChanged( const DocumentContentChange& ) = 0; virtual void onDocumentUndoRedo( const UndoRedo& eventType ) = 0; virtual void onDocumentCursorChange( const TextPosition& ) = 0; virtual void onDocumentSelectionChange( const TextRange& ) = 0; @@ -131,6 +136,8 @@ class EE_API TextDocument { String getText( const TextRange& range ) const; + String getText() const; + String getSelectedText() const; String::StringBaseType getChar( const TextPosition& position ) const; @@ -476,7 +483,7 @@ class EE_API TextDocument { void notifyDocumentLoaded(); - void notifyTextChanged(); + void notifyTextChanged( const DocumentContentChange& ); void notifyCursorChanged(); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 96071091c..0424fddd1 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -689,7 +689,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void updateEditor(); - virtual void onDocumentTextChanged(); + virtual void onDocumentTextChanged( const DocumentContentChange& ); virtual void onDocumentCursorChange( const TextPosition& ); diff --git a/include/eepp/ui/uiconsole.hpp b/include/eepp/ui/uiconsole.hpp index 75310eb07..cd1466347 100644 --- a/include/eepp/ui/uiconsole.hpp +++ b/include/eepp/ui/uiconsole.hpp @@ -201,7 +201,7 @@ class EE_API UIConsole : public UIWidget, virtual Uint32 onFocusLoss(); - virtual void onDocumentTextChanged(); + virtual void onDocumentTextChanged( const DocumentContentChange& ); virtual void onDocumentCursorChange( const TextPosition& ); diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index e5d394fa6..68bdd7a86 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -179,7 +179,7 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client { virtual Int32 selCurEnd(); - virtual void onDocumentTextChanged(); + virtual void onDocumentTextChanged( const DocumentContentChange& ); virtual void onDocumentCursorChange( const TextPosition& ); diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index bf03a4710..e8de7f500 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -186,7 +186,7 @@ true - --with-mojoal --with-mold-linker gmake + --with-mojoal gmake premake4 %{buildDir}../../../ ProjectExplorer.ProcessStep @@ -228,7 +228,7 @@ true - --with-mold-linker --with-debug-symbols --with-mojoal gmake + --with-debug-symbols --with-mojoal gmake premake4 %{buildDir}../../../ ProjectExplorer.ProcessStep diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index fa8ddf981..09f48e13f 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -57,6 +57,7 @@ bool TextDocument::isEmpty() { } void TextDocument::reset() { + auto oldSelection = sanitizeRange( mSelection ); mFilePath = mDefaultFileName; mFileRealPath = FileInfo(); mSelection.set( { 0, 0 }, { 0, 0 } ); @@ -65,7 +66,8 @@ void TextDocument::reset() { mSyntaxDefinition = SyntaxDefinitionManager::instance()->getPlainStyle(); mUndoStack.clear(); cleanChangeId(); - notifyTextChanged(); + if ( oldSelection.isValid() ) + notifyTextChanged( { { oldSelection.end(), oldSelection.start() }, "" } ); notifyCursorChanged(); notifySelectionChanged(); } @@ -167,7 +169,7 @@ TextDocument::LoadStatus TextDocument::loadFromStream( IOStream& file, std::stri if ( mAutoDetectIndentType ) guessIndentType(); - notifyTextChanged(); + notifyTextChanged( { { { 0, 0 }, { 0, 0 } }, "" } ); if ( mVerbose ) Log::info( "Document \"%s\" loaded in %.2fms.", path.c_str(), @@ -454,7 +456,7 @@ TextDocument::LoadStatus TextDocument::reload() { mFileRealPath = FileInfo::isLink( mFilePath ) ? FileInfo( FileInfo( mFilePath ).linksTo() ) : FileInfo( mFilePath ); resetSyntax(); - notifyTextChanged(); + notifyTextChanged( { { { 0, 0 }, { 0, 0 } }, "" } ); setSelection( sanitizePosition( selection.start() ) ); } return ret; @@ -498,6 +500,7 @@ bool TextDocument::save( IOStream& stream, bool keepUndoRedoStatus ) { if ( !keepUndoRedoStatus && mTrimTrailingWhitespaces && text.size() > 1 && whitespaces.find( text[text.size() - 2] ) != std::string::npos ) { size_t pos = text.find_last_not_of( whitespaces ); + size_t oriSize = text.size(); if ( pos != std::string::npos ) { text.erase( pos + 1 ); text += nl; @@ -506,7 +509,10 @@ bool TextDocument::save( IOStream& stream, bool keepUndoRedoStatus ) { } mLines[i].setText( text ); notifyLineChanged( i ); - notifyTextChanged(); + notifyTextChanged( + { { { static_cast( i ), static_cast( oriSize ) }, + { static_cast( i ), static_cast( text.size() - 1 ) } }, + "" } ); } if ( i == lastLine ) { if ( !text.empty() && text[text.size() - 1] == '\n' ) { @@ -519,7 +525,11 @@ bool TextDocument::save( IOStream& stream, bool keepUndoRedoStatus ) { text[text.size() - 1] != '\n' ) { text += "\n"; mLines.emplace_back( TextDocumentLine( "\n" ) ); - notifyTextChanged(); + notifyTextChanged( { { TextPosition{ static_cast( i ), + static_cast( mLines[i].size() - 1 ) }, + TextPosition{ static_cast( i ), + static_cast( mLines[i].size() - 1 ) } }, + "\n" } ); notifyLineChanged( i ); notifyLineCountChanged( lastLine, lastLine + 1 ); } @@ -650,6 +660,10 @@ String TextDocument::getText( const TextRange& range ) const { return String::join( lines, -1 ); } +String TextDocument::getText() const { + return getText( getDocRange() ); +} + String TextDocument::getSelectedText() const { return getText( getSelection() ); } @@ -694,7 +708,7 @@ TextPosition TextDocument::insert( TextPosition position, const String& text, mUndoStack.pushSelection( undoStack, getSelection(), time ); mUndoStack.pushRemove( undoStack, { position, cursor }, time ); - notifyTextChanged(); + notifyTextChanged( { { position, position }, text } ); if ( lineCount != mLines.size() ) { notifyLineCountChanged( lineCount, mLines.size() ); @@ -778,7 +792,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const if ( lines().empty() ) { mLines.emplace_back( String( "\n" ) ); } - notifyTextChanged(); + notifyTextChanged( { range, "" } ); notifyLineChanged( range.start().line() ); } @@ -1390,6 +1404,8 @@ void TextDocument::print() const { } TextRange TextDocument::sanitizeRange( const TextRange& range ) const { + if ( !range.isValid() ) + return range; return { sanitizePosition( range.start() ), sanitizePosition( range.end() ) }; } @@ -1953,9 +1969,9 @@ void TextDocument::setNonWordChars( const String& nonWordChars ) { mNonWordChars = nonWordChars; } -void TextDocument::notifyTextChanged() { +void TextDocument::notifyTextChanged( const DocumentContentChange& change ) { for ( auto& client : mClients ) { - client->onDocumentTextChanged(); + client->onDocumentTextChanged( change ); } } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 4e4346629..84dbe2cee 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1439,7 +1439,7 @@ void UICodeEditor::updateEditor() { mDirtyScroll = false; } -void UICodeEditor::onDocumentTextChanged() { +void UICodeEditor::onDocumentTextChanged( const DocumentContentChange& ) { invalidateDraw(); checkMatchingBrackets(); sendCommonEvent( Event::OnTextChanged ); diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 3d673c38f..5ede815a4 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -895,7 +895,7 @@ Uint32 UIConsole::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) { return UIWidget::onMouseLeave( Pos, Flags ); } -void UIConsole::onDocumentTextChanged() { +void UIConsole::onDocumentTextChanged( const DocumentContentChange& ) { resetCursor(); invalidateDraw(); diff --git a/src/eepp/ui/uitextedit.cpp b/src/eepp/ui/uitextedit.cpp index 3985b3af2..bbf94091c 100644 --- a/src/eepp/ui/uitextedit.cpp +++ b/src/eepp/ui/uitextedit.cpp @@ -71,7 +71,7 @@ void UITextEdit::wrapText( const Float& maxWidth ) { } String UITextEdit::getText() const { - return mDoc->getText( { mDoc->startOfDoc(), mDoc->endOfDoc() } ); + return mDoc->getText(); } void UITextEdit::setText( const String& text ) { diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 646061084..74d307cff 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -376,7 +376,7 @@ Int32 UITextInput::selCurEnd() { return mDoc.getSelection().end().column(); } -void UITextInput::onDocumentTextChanged() { +void UITextInput::onDocumentTextChanged( const DocumentContentChange& ) { Vector2f offSet = mRealAlignOffset; const String& text = mDoc.line( 0 ).getText(); diff --git a/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp b/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp index e4522bb5a..88e4345bf 100644 --- a/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientprotocol.hpp @@ -2,6 +2,7 @@ #define ECODE_LSPCLIENTPROTOCOL_HPP #include +#include #include using namespace EE::UI::Doc; @@ -107,6 +108,89 @@ struct LSPShowMessageParams { std::string message; }; +struct LSPTextDocumentContentChangeEvent { + TextRange range; + std::string text; +}; + +enum class LSPDiagnosticSeverity { + Unknown = 0, + Error = 1, + Warning = 2, + Information = 3, + Hint = 4, +}; + +struct LSPDiagnosticRelatedInformation { + // empty url / invalid range when absent + LSPLocation location; + std::string message; +}; + +struct LSPDiagnostic { + TextRange range; + LSPDiagnosticSeverity severity; + std::string code; + std::string source; + std::string message; + std::vector relatedInformation; +}; + +struct LSPPublishDiagnosticsParams { + URI uri; + std::vector diagnostics; +}; + +struct LSPCommand { + std::string title; + std::string command; + // pretty opaque + nlohmann::json arguments; +}; + +struct LSPVersionedTextDocumentIdentifier { + URI uri; + int version = -1; +}; + +using LSPTextEdit = LSPTextDocumentContentChangeEvent; + +struct LSPTextDocumentEdit { + LSPVersionedTextDocumentIdentifier textDocument; + std::vector edits; +}; + +struct LSPWorkspaceEdit { + // supported part for now + std::map> changes; + std::vector documentChanges; +}; + +struct LSPCodeAction { + std::string title; + std::string kind; + std::vector diagnostics; + LSPWorkspaceEdit edit; + LSPCommand command; +}; + +enum class LSPWorkDoneProgressKind { Begin, Report, End }; + +struct LSPWorkDoneProgressValue { + LSPWorkDoneProgressKind kind; + std::string title; + std::string message; + bool cancellable; + unsigned percentage; +}; +template struct LSPProgressParams { + // number or string + nlohmann::json token; + T value; +}; + +using LSPWorkDoneProgressParams = LSPProgressParams; + } // namespace ecode #endif // ECODE_LSPCLIENTPROTOCOL_HPP diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index bfd5cd8fa..35b49e364 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -28,19 +28,19 @@ static const char* MEMBER_START = "start"; static const char* MEMBER_END = "end"; static const char* MEMBER_POSITION = "position"; // static const char* MEMBER_POSITIONS = "positions"; -// static const char* MEMBER_LOCATION = "location"; +static const char* MEMBER_LOCATION = "location"; static const char* MEMBER_RANGE = "range"; static const char* MEMBER_LINE = "line"; static const char* MEMBER_CHARACTER = "character"; // static const char* MEMBER_KIND = "kind"; -// static const char* MEMBER_LABEL = "label"; -// static const char* MEMBER_DOCUMENTATION = "documentation"; -// static const char* MEMBER_DETAIL = "detail"; +// static const char* MEMBER_LABEL = "label"; +// static const char* MEMBER_DOCUMENTATION = "documentation"; +// static const char* MEMBER_DETAIL = "detail"; // static const char* MEMBER_COMMAND = "command"; // static const char* MEMBER_EDIT = "edit"; // static const char* MEMBER_TITLE = "title"; // static const char* MEMBER_ARGUMENTS = "arguments"; -// static const char* MEMBER_DIAGNOSTICS = "diagnostics"; +static const char* MEMBER_DIAGNOSTICS = "diagnostics"; static const char* MEMBER_TARGET_URI = "targetUri"; static const char* MEMBER_TARGET_RANGE = "targetRange"; static const char* MEMBER_TARGET_SELECTION_RANGE = "targetSelectionRange"; @@ -81,6 +81,10 @@ static json toJson( const TextPosition& pos ) { return json{ { MEMBER_LINE, pos.line() }, { MEMBER_CHARACTER, pos.column() } }; } +static json toJson( const TextRange& pos ) { + return json{ { MEMBER_START, toJson( pos.start() ) }, { MEMBER_END, toJson( pos.end() ) } }; +} + static json workspaceFolder( const LSPWorkspaceFolder& response ) { return json{ { MEMBER_URI, response.uri.toString() }, { "name", response.name } }; } @@ -94,6 +98,15 @@ static json toJson( const std::vector& l ) { return result; } +static json toJson( const std::vector& changes ) { + json result; + for ( const auto& change : changes ) { + result.push_back( + { { MEMBER_RANGE, toJson( change.range ) }, { MEMBER_TEXT, change.text } } ); + } + return result; +} + static TextPosition parsePosition( const json& m ) { auto line = m[MEMBER_LINE].get(); auto column = m[MEMBER_CHARACTER].get(); @@ -248,6 +261,110 @@ static void fromJson( LSPServerCapabilities& caps, const json& json ) { caps.selectionRangeProvider = toBoolOrObject( json, "selectionRangeProvider" ); } +static std::vector parseDiagnosticsArr( const json& result ) { + std::vector ret; + for ( const auto& vdiag : result ) { + auto diag = vdiag; + auto range = parseRange( diag[MEMBER_RANGE] ); + auto severity = static_cast( diag["severity"].get() ); + auto code = diag.at( "code" ).get(); + auto source = diag.at( "source" ).get(); + auto message = diag.at( MEMBER_MESSAGE ).get(); + std::vector relatedInfoList; + if ( diag.contains( "relatedInformation" ) ) { + const auto relatedInfo = diag.at( "relatedInformation" ); + for ( const auto& vrelated : relatedInfo ) { + auto related = vrelated; + auto relLocation = parseLocation( related.at( MEMBER_LOCATION ) ); + auto relMessage = related.at( MEMBER_MESSAGE ).get(); + relatedInfoList.push_back( { relLocation, relMessage } ); + } + } + ret.push_back( { range, severity, code, source, message, relatedInfoList } ); + } + return ret; +} + +static LSPPublishDiagnosticsParams parseDiagnostics( const json& result ) { + LSPPublishDiagnosticsParams ret; + ret.uri = URI( result.at( MEMBER_URI ).get() ); + ret.diagnostics = parseDiagnosticsArr( result.at( MEMBER_DIAGNOSTICS ) ); + return ret; +} + +/*static std::vector parseTextEdit( const json& result ) { + std::vector ret; + const auto textEdits = result; + for ( const auto& redit : textEdits ) { + auto edit = redit; + auto text = edit.at( "newText" ).get(); + auto range = parseRange( edit.at( MEMBER_RANGE ) ); + ret.push_back( { range, text } ); + } + return ret; +} + +static void fromJson( LSPVersionedTextDocumentIdentifier& id, const json& json ) { + if ( json.is_object() ) { + auto ob = json; + id.uri = URI( ob.at( MEMBER_URI ).get() ); + id.version = ob.contains( MEMBER_VERSION ) ? ob.at( MEMBER_VERSION ).get() : -1; + } +} + +static LSPTextDocumentEdit parseTextDocumentEdit( const json& result ) { + LSPTextDocumentEdit ret; + auto ob = result; + fromJson( ret.textDocument, ob.at( "textDocument" ) ); + ret.edits = parseTextEdit( ob.at( "edits" ) ); + return ret; +} + +static LSPWorkspaceEdit parseWorkSpaceEdit( const json& result ) { + LSPWorkspaceEdit ret; + auto changes = result.at( "changes" ); + for ( auto it = changes.begin(); it != changes.end(); ++it ) { + ret.changes.insert( std::pair>( + URI( it.key() ), parseTextEdit( it.value() ) ) ); + } + auto documentChanges = result.at( "documentChanges" ); + // resourceOperations not supported for now + for ( auto edit : documentChanges ) { + ret.documentChanges.push_back( parseTextDocumentEdit( edit ) ); + } + return ret; +} + +static LSPCommand parseCommand( const json& result ) { + auto title = result.at( MEMBER_TITLE ).get(); + auto command = result.at( MEMBER_COMMAND ).get(); + auto args = result.at( MEMBER_ARGUMENTS ); + return { title, command, args }; +} + +static std::vector parseCodeAction( const json& result ) { + std::vector ret; + const auto codeActions = result; + for ( const auto& vaction : codeActions ) { + auto action = vaction; + // entry could be Command or CodeAction + if ( !action.at( MEMBER_COMMAND ).is_string() ) { + // CodeAction + auto title = action.at( MEMBER_TITLE ).get(); + auto kind = action.at( MEMBER_KIND ).get(); + auto command = parseCommand( action.at( MEMBER_COMMAND ) ); + auto edit = parseWorkSpaceEdit( action.at( MEMBER_EDIT ) ); + auto diagnostics = parseDiagnostics( action.at( MEMBER_DIAGNOSTICS ) ); + ret.push_back( { title, kind, diagnostics, edit, command } ); + } else { + // Command + auto command = parseCommand( action ); + ret.push_back( { command.title, std::string(), {}, {}, command } ); + } + } + return ret; +}*/ + LSPClientServer::LSPClientServer( LSPClientServerManager* manager, const String::HashType& id, const LSPDefinition& lsp, const std::string& rootPath ) : mManager( manager ), mId( id ), mLSP( lsp ), mRootPath( rootPath ) {} @@ -378,23 +495,26 @@ LSPClientServer::RequestHandle LSPClientServer::didSave( const URI& document, } LSPClientServer::RequestHandle LSPClientServer::didSave( TextDocument* doc ) { - return didSave( doc->getURI(), doc->getText( doc->getDocRange() ).toUtf8() ); + return didSave( doc->getURI(), mCapabilities.textDocumentSync.save.includeText + ? doc->getText().toUtf8() + : "" ); } -LSPClientServer::RequestHandle LSPClientServer::didChange( const URI& document, int version, - const std::string& text ) { +LSPClientServer::RequestHandle +LSPClientServer::didChange( const URI& document, int version, const std::string& text, + const std::vector& change ) { auto params = textDocumentParams( document, version ); - if ( !text.empty() ) - params["contentChanges"] = { json{ MEMBER_TEXT, text } }; + params["contentChanges"] = !text.empty() ? json{ json{ MEMBER_TEXT, text } } : toJson( change ); return send( newRequest( "textDocument/didChange", params ) ); } -LSPClientServer::RequestHandle LSPClientServer::didChange( TextDocument* doc ) { +LSPClientServer::RequestHandle +LSPClientServer::didChange( TextDocument* doc, const std::vector& change ) { Lock l( mClientsMutex ); auto it = mClients.find( doc ); if ( it != mClients.end() ) return didChange( doc->getURI(), it->second->getVersion(), - doc->getText( doc->getDocRange() ).toUtf8() ); + change.empty() ? doc->getText().toUtf8() : "", change ); return RequestHandle(); } @@ -403,7 +523,11 @@ void LSPClientServer::updateDirty() { for ( auto& client : mClients ) { if ( client.second->isDirty() ) { TextDocument* doc = client.first; - mManager->getThreadPool()->run( [this, doc]() { didChange( doc ); } ); + LSPDocumentClient* docClient = client.second.get(); + mManager->getThreadPool()->run( [this, doc, docClient]() { + didChange( doc, docClient->getDocChange() ); + docClient->clearDocChange(); + } ); client.second->resetDirty(); } } @@ -448,25 +572,8 @@ LSPClientServer::RequestHandle LSPClientServer::documentSymbols( const URI& docu return send( newRequest( "textDocument/documentSymbol", params ), h, eh ); } -/*enum class LSPWorkDoneProgressKind { Begin, Report, End }; - -struct LSPWorkDoneProgressValue { - LSPWorkDoneProgressKind kind; - std::string title; - std::string message; - bool cancellable; - unsigned percentage; -}; -template struct LSPProgressParams { - // number or string - json token; - T value; -}; - -using LSPWorkDoneProgressParams = LSPProgressParams; - void fromJson( LSPWorkDoneProgressValue& value, const json& json ) { - if ( json ) { + if ( !json.empty() ) { auto ob = json; auto kind = ob["kind"].get(); if ( kind == "begin" ) { @@ -476,43 +583,59 @@ void fromJson( LSPWorkDoneProgressValue& value, const json& json ) { } else if ( kind == "end" ) { value.kind = LSPWorkDoneProgressKind::End; } - value.title = ob["title"].get(); - value.message = ob["message"].get(); - value.cancellable = ob["cancellable"].get(); - value.percentage = ob["percentage"].get(); + value.title = ob.contains( "title" ) ? ob["title"].get() : ""; + value.message = ob.contains( "message" ) ? ob["message"].get() : ""; + value.cancellable = ob.contains( "cancellable" ) ? ob["cancellable"].get() : false; + value.percentage = ob.contains( "percentage" ) ? ob["percentage"].get() : 0; } } template static LSPProgressParams parseProgress( const json& json ) { LSPProgressParams ret; - ret.token = json["token"]; - fromJson( ret.value, json["value"] ); + ret.token = json.at( "token" ); + fromJson( ret.value, json.at( "value" ) ); return ret; } static LSPWorkDoneProgressParams parseWorkDone( const json& json ) { return parseProgress( json ); -}*/ +} static json newError( const LSPErrorCode& code, const std::string& msg ) { return json{ { MEMBER_ERROR, { { MEMBER_CODE, static_cast( code ) }, { MEMBER_MESSAGE, msg } } } }; } +void LSPClientServer::publishDiagnostics( const json& msg ) { + // should emmit event somewhere + auto res = parseDiagnostics( msg[MEMBER_PARAMS] ); + Log::debug( "LSPClientServer::publishDiagnostics: %s", res.uri.toString().c_str() ); +} + +void LSPClientServer::workDoneProgress( const LSPWorkDoneProgressParams& workDoneParams ) { + // should emmit event somewhere + Log::debug( "LSPClientServer::workDoneProgress: %s", + workDoneParams.token.is_string() + ? workDoneParams.token.get().c_str() + : String::toString( workDoneParams.token.get() ).c_str() ); +} + void LSPClientServer::processNotification( const json& msg ) { - Log::warning( "LSPClientServer::processNotification server %s: %s", mLSP.name.c_str(), - msg.dump().c_str() ); auto method = msg[MEMBER_METHOD].get(); if ( method == "textDocument/publishDiagnostics" ) { - // publishDiagnostics( msg ); + publishDiagnostics( msg ); + return; } else if ( method == ( "window/showMessage" ) ) { // showMessage( msg ); } else if ( method == ( "window/logMessage" ) ) { // logMessage( msg ); } else if ( method == ( "$/progress" ) ) { - // workDoneProgress( parseWorkDone( msg["params"] ) ); + workDoneProgress( parseWorkDone( msg[MEMBER_PARAMS] ) ); + return; } else { } + Log::debug( "LSPClientServer::processNotification server %s: %s", mLSP.name.c_str(), + msg.dump().c_str() ); } void LSPClientServer::processRequest( const json& msg ) { @@ -662,7 +785,8 @@ void LSPClientServer::initialize() { { "selectionRange", json{ { "dynamicRegistration", false } } }, { "hover", json{ { "contentFormat", { "markdown", "plaintext" } } } } }, }, - { "window", json{ { "workDoneProgress", true } } } }; + { "window", json{ { "workDoneProgress", true } } }, + { "general", json{ { "positionEncodings", json::array( { "utf-32" } ) } } } }; json params{ { "processId", Sys::getProcessID() }, { "capabilities", capabilities }, diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index 95b1e09cd..83d5e93ec 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -77,10 +77,12 @@ class LSPClientServer { LSPClientServer::RequestHandle didClose( TextDocument* document ); - LSPClientServer::RequestHandle didChange( const URI& document, int version, - const std::string& text ); + LSPClientServer::RequestHandle + didChange( const URI& document, int version, const std::string& text, + const std::vector& change = {} ); - LSPClientServer::RequestHandle didChange( TextDocument* doc ); + LSPClientServer::RequestHandle + didChange( TextDocument* doc, const std::vector& change = {} ); LSPClientServer::RequestHandle documentDefinition( const URI& document, const TextPosition& pos ); @@ -104,6 +106,10 @@ class LSPClientServer { didChangeWorkspaceFolders( const std::vector& added, const std::vector& removed ); + void publishDiagnostics( const json& msg ); + + void workDoneProgress( const LSPWorkDoneProgressParams& workDoneParams ); + protected: LSPClientServerManager* mManager{ nullptr }; String::HashType mId; diff --git a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp index cd4b93354..af4e021c3 100644 --- a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp +++ b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp @@ -15,9 +15,11 @@ LSPDocumentClient::LSPDocumentClient( LSPClientServer* server, TextDocument* doc LSPDocumentClient::~LSPDocumentClient() {} -void LSPDocumentClient::onDocumentTextChanged() { +void LSPDocumentClient::onDocumentTextChanged( const DocumentContentChange& change ) { mModified = true; ++mVersion; + if ( !change.text.empty() || change.range.start() != change.range.end() ) + mDocChange.push_back( change ); mLastModified.restart(); } @@ -64,6 +66,14 @@ int LSPDocumentClient::getVersion() const { return mVersion; } +const std::vector& LSPDocumentClient::getDocChange() const { + return mDocChange; +} + +void LSPDocumentClient::clearDocChange() { + mDocChange.clear(); +} + void LSPDocumentClient::notifyOpen() { eeASSERT( mDoc ); mServer->didOpen( mDoc, ++mVersion ); diff --git a/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp b/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp index 515d7cad7..24b4c4fe2 100644 --- a/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp +++ b/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp @@ -18,7 +18,7 @@ class LSPDocumentClient : public TextDocument::Client { ~LSPDocumentClient(); - virtual void onDocumentTextChanged(); + virtual void onDocumentTextChanged( const DocumentContentChange& change ); virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& eventType ); virtual void onDocumentCursorChange( const TextPosition& ); virtual void onDocumentSelectionChange( const TextRange& ); @@ -41,12 +41,16 @@ class LSPDocumentClient : public TextDocument::Client { int getVersion() const; + const std::vector& getDocChange() const; + + void clearDocChange(); protected: LSPClientServer* mServer{ nullptr }; TextDocument* mDoc{ nullptr }; bool mModified{ false }; int mVersion{ 0 }; Clock mLastModified; + std::vector mDocChange; }; } // namespace ecode