mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-29 17:46:29 +03:00
ecode: Added textDocument/rename support ("Rename Symbol Under Cursor").
This commit is contained in:
@@ -36,6 +36,8 @@ class EE_API SyntaxHighlighter {
|
||||
|
||||
std::string getTokenTypeAt( const TextPosition& pos );
|
||||
|
||||
SyntaxTokenPosition getTokenPositionAt( const TextPosition& pos );
|
||||
|
||||
protected:
|
||||
TextDocument* mDoc;
|
||||
std::map<size_t, TokenizedLine> mLines;
|
||||
|
||||
@@ -18,6 +18,12 @@ struct EE_API SyntaxToken {
|
||||
size_t len{ 0 };
|
||||
};
|
||||
|
||||
struct EE_API SyntaxTokenPosition {
|
||||
std::string type;
|
||||
Int64 pos{ 0 };
|
||||
size_t len{ 0 };
|
||||
};
|
||||
|
||||
struct EE_API SyntaxTokenComplete {
|
||||
std::string type;
|
||||
std::string text;
|
||||
|
||||
@@ -547,6 +547,14 @@ class EE_API TextDocument {
|
||||
|
||||
SyntaxHighlighter* getHighlighter() const;
|
||||
|
||||
TextRange getWordRangeInPosition( const TextPosition& pos );
|
||||
|
||||
TextRange getWordRangeInPosition();
|
||||
|
||||
String getWordInPosition( const TextPosition& pos );
|
||||
|
||||
String getWordInPosition();
|
||||
|
||||
protected:
|
||||
friend class UndoStack;
|
||||
|
||||
|
||||
@@ -129,4 +129,19 @@ std::string SyntaxHighlighter::getTokenTypeAt( const TextPosition& pos ) {
|
||||
return "normal";
|
||||
}
|
||||
|
||||
SyntaxTokenPosition SyntaxHighlighter::getTokenPositionAt( const TextPosition& pos ) {
|
||||
if ( !pos.isValid() || pos.line() < 0 || pos.line() >= (Int64)mDoc->linesCount() )
|
||||
return {};
|
||||
const std::vector<SyntaxToken>& tokens = getLine( pos.line() );
|
||||
if ( tokens.empty() )
|
||||
return {};
|
||||
Int64 col = 0;
|
||||
for ( const auto& token : tokens ) {
|
||||
col += token.len;
|
||||
if ( col > pos.column() )
|
||||
return { token.type, static_cast<Int64>( col - token.len ), token.len };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Doc
|
||||
|
||||
@@ -1567,6 +1567,27 @@ void TextDocument::selectToNextWord() {
|
||||
mergeSelection();
|
||||
}
|
||||
|
||||
TextRange TextDocument::getWordRangeInPosition( const TextPosition& pos ) {
|
||||
if ( mHighlighter ) {
|
||||
auto type( mHighlighter->getTokenPositionAt( pos ) );
|
||||
return { { pos.line(), type.pos }, { pos.line(), type.pos + (Int64)type.len } };
|
||||
}
|
||||
|
||||
return { nextWordBoundary( pos, false ), previousWordBoundary( pos, false ) };
|
||||
}
|
||||
|
||||
TextRange TextDocument::getWordRangeInPosition() {
|
||||
return getWordRangeInPosition( getSelection().start() );
|
||||
}
|
||||
|
||||
String TextDocument::getWordInPosition( const TextPosition& pos ) {
|
||||
return getText( getWordRangeInPosition( pos ) );
|
||||
}
|
||||
|
||||
String TextDocument::getWordInPosition() {
|
||||
return getWordInPosition( getSelection().start() );
|
||||
}
|
||||
|
||||
void TextDocument::selectWord( bool withMulticursor ) {
|
||||
if ( !hasSelection() ) {
|
||||
setSelection( { nextWordBoundary( getSelection().start(), false ),
|
||||
|
||||
@@ -722,14 +722,16 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
|
||||
mKeyBindings["lsp-go-to-definition"] = "f2";
|
||||
mKeyBindings["lsp-symbol-info"] = "f1";
|
||||
mKeyBindings["lsp-symbol-code-action"] = "alt+return";
|
||||
mKeyBindings["lsp-rename-symbol-under-cursor"] = "ctrl+shift+r";
|
||||
}
|
||||
|
||||
if ( j.contains( "keybindings" ) ) {
|
||||
auto& kb = j["keybindings"];
|
||||
auto list = {
|
||||
"lsp-go-to-definition", "lsp-go-to-declaration", "lsp-go-to-implementation",
|
||||
"lsp-go-to-type-definition", "lsp-switch-header-source", "lsp-symbol-info",
|
||||
"lsp-symbol-references", "lsp-memory-usage", "lsp-symbol-code-action" };
|
||||
auto list = { "lsp-go-to-definition", "lsp-go-to-declaration",
|
||||
"lsp-go-to-implementation", "lsp-go-to-type-definition",
|
||||
"lsp-switch-header-source", "lsp-symbol-info",
|
||||
"lsp-symbol-references", "lsp-memory-usage",
|
||||
"lsp-symbol-code-action", "lsp-rename-symbol-under-cursor" };
|
||||
for ( const auto& key : list ) {
|
||||
if ( kb.contains( key ) ) {
|
||||
if ( !kb[key].empty() )
|
||||
@@ -905,6 +907,29 @@ void LSPClientPlugin::codeAction( UICodeEditor* editor ) {
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientPlugin::renameSymbol( UICodeEditor* editor ) {
|
||||
UIMessageBox* msgBox = UIMessageBox::New(
|
||||
UIMessageBox::INPUT, editor->getUISceneNode()->i18n(
|
||||
"new_symbol_under_cursor_name",
|
||||
"New name (caution: not all references may be replaced)" ) );
|
||||
msgBox->setTitle( editor->getUISceneNode()->i18n( "rename", "Rename" ) );
|
||||
msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } );
|
||||
TextPosition pos = editor->getDocument().getSelection().start();
|
||||
msgBox->getTextInput()->setText(
|
||||
editor->getDocument().getWordInPosition( editor->getDocument().getSelection().start() ) );
|
||||
msgBox->getTextInput()->getDocument().selectAll();
|
||||
msgBox->showWhenReady();
|
||||
msgBox->addEventListener( Event::OnConfirm, [this, pos, editor, msgBox]( const Event* ) {
|
||||
String newName( msgBox->getTextInput()->getText() );
|
||||
mClientManager.renameSymbol( editor->getDocumentRef()->getURI(), pos, newName );
|
||||
msgBox->closeWindow();
|
||||
} );
|
||||
msgBox->addEventListener( Event::OnClose, [&]( const Event* ) {
|
||||
if ( mManager->getSplitter() && mManager->getSplitter()->getCurWidget() )
|
||||
mManager->getSplitter()->getCurWidget()->setFocus();
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientPlugin::onRegister( UICodeEditor* editor ) {
|
||||
Lock l( mDocMutex );
|
||||
mDocs.insert( editor->getDocumentRef().get() );
|
||||
@@ -921,6 +946,9 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) {
|
||||
getAndGoToLocation( editor, "textDocument/definition" );
|
||||
} );
|
||||
|
||||
doc.setCommand( "lsp-rename-symbol-under-cursor",
|
||||
[this, editor]() { renameSymbol( editor ); } );
|
||||
|
||||
doc.setCommand( "lsp-go-to-declaration", [&, editor]() {
|
||||
getAndGoToLocation( editor, "textDocument/declaration" );
|
||||
} );
|
||||
@@ -1060,6 +1088,9 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me
|
||||
if ( cap.implementationProvider )
|
||||
addFn( "lsp-go-to-implementation", "Go To Implementation" );
|
||||
|
||||
if ( cap.renameProvider )
|
||||
addFn( "lsp-rename-symbol-under-cursor", "Rename Symbol Under Cursor" );
|
||||
|
||||
if ( cap.referencesProvider )
|
||||
addFn( "lsp-symbol-references", "Find References to Symbol Under Cursor" );
|
||||
|
||||
|
||||
@@ -171,6 +171,8 @@ class LSPClientPlugin : public UICodeEditorPlugin {
|
||||
LSPSymbolInformationList&& res );
|
||||
|
||||
void processDiagnosticsCodeAction( const PluginMessage& msg );
|
||||
|
||||
void renameSymbol( UICodeEditor* editor );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -508,9 +508,9 @@ static LSPWorkspaceEdit parseWorkSpaceEdit( const json& result ) {
|
||||
}
|
||||
}
|
||||
if ( result.contains( "documentChanges" ) ) {
|
||||
auto& documentChanges = result.at( "documentChanges" );
|
||||
const auto& documentChanges = result.at( "documentChanges" );
|
||||
// resourceOperations not supported for now
|
||||
for ( auto& edit : documentChanges ) {
|
||||
for ( const auto& edit : documentChanges ) {
|
||||
ret.documentChanges.push_back( parseTextDocumentEdit( edit ) );
|
||||
}
|
||||
}
|
||||
@@ -520,7 +520,7 @@ static LSPWorkspaceEdit parseWorkSpaceEdit( const json& result ) {
|
||||
static LSPCommand parseCommand( const json& result ) {
|
||||
auto title = result.at( MEMBER_TITLE ).get<std::string>();
|
||||
auto command = result.at( MEMBER_COMMAND ).get<std::string>();
|
||||
auto& args = result.at( MEMBER_ARGUMENTS );
|
||||
const auto& args = result.at( MEMBER_ARGUMENTS );
|
||||
return { title, command, args };
|
||||
}
|
||||
|
||||
@@ -908,6 +908,13 @@ static json applyWorkspaceEditResponse( const PluginIDType& msgid,
|
||||
return j;
|
||||
}
|
||||
|
||||
static json renameParams( const URI& document, const TextPosition& pos,
|
||||
const std::string& newName ) {
|
||||
auto params = textDocumentPositionParams( document, pos );
|
||||
params["newName"] = newName;
|
||||
return params;
|
||||
}
|
||||
|
||||
void LSPClientServer::registerCapabilities( const json& jcap ) {
|
||||
if ( !jcap.is_object() || !jcap.contains( "registrations" ) ||
|
||||
!jcap["registrations"].is_array() )
|
||||
@@ -923,6 +930,9 @@ void LSPClientServer::registerCapabilities( const json& jcap ) {
|
||||
} else if ( reg["method"] == "textDocument/documentSymbol" ) {
|
||||
mCapabilities.documentSymbolProvider = true;
|
||||
registered = true;
|
||||
} else if ( reg["method"] == "textDocument/rename" ) {
|
||||
mCapabilities.renameProvider = true;
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -975,6 +985,7 @@ void LSPClientServer::initialize() {
|
||||
{ "selectionRange", json{ { "dynamicRegistration", false } } },
|
||||
{ "hover", json{ { "contentFormat", { "markdown", "plaintext" } } } },
|
||||
{ "completion", completionItem },
|
||||
{ "rename", json{ { "dynamicRegistration", true } } },
|
||||
} },
|
||||
{ "window", json{ { "workDoneProgress", true },
|
||||
{ "showMessage", showMessage },
|
||||
@@ -1812,6 +1823,20 @@ LSPClientServer::documentFormatting( const URI& document, const json& options,
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientServer::documentRename( const URI& document, const TextPosition& pos,
|
||||
const std::string& newName, const JsonReplyHandler& h ) {
|
||||
auto params = renameParams( document, pos, newName );
|
||||
sendAsync( newRequest( "textDocument/rename", params ), h );
|
||||
}
|
||||
|
||||
void LSPClientServer::documentRename( const URI& document, const TextPosition& pos,
|
||||
const std::string& newName, const WorkspaceEditHandler& h ) {
|
||||
documentRename( document, pos, newName, [h]( const IdType& id, const json& json ) {
|
||||
if ( h )
|
||||
h( id, parseWorkSpaceEdit( json ) );
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientServer::memoryUsage( const JsonReplyHandler& h ) {
|
||||
return sendAsync( newRequest( "$/memoryUsage" ), h );
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class LSPClientServer {
|
||||
using SignatureHelpHandler = ReplyHandler<LSPSignatureHelp>;
|
||||
using LocationHandler = ReplyHandler<std::vector<LSPLocation>>;
|
||||
using TextEditArrayHandler = ReplyHandler<std::vector<LSPTextEdit>>;
|
||||
using WorkspaceEditHandler = ReplyHandler<LSPWorkspaceEdit>;
|
||||
|
||||
class LSPRequestHandle : public PluginRequestHandle {
|
||||
public:
|
||||
@@ -196,6 +197,12 @@ class LSPClientServer {
|
||||
LSPRequestHandle documentFormatting( const URI& document, const json& options,
|
||||
const TextEditArrayHandler& h );
|
||||
|
||||
void documentRename( const URI& document, const TextPosition& pos,
|
||||
const std::string& newName, const JsonReplyHandler& h );
|
||||
|
||||
void documentRename( const URI& document, const TextPosition& pos,
|
||||
const std::string& newName, const WorkspaceEditHandler& h );
|
||||
|
||||
void memoryUsage( const JsonReplyHandler& h );
|
||||
|
||||
void memoryUsage();
|
||||
|
||||
@@ -186,6 +186,17 @@ void LSPClientServerManager::applyWorkspaceEdit(
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientServerManager::renameSymbol( const URI& uri, const TextPosition& pos,
|
||||
const std::string& newName ) {
|
||||
auto* server = getOneLSPClientServer( uri );
|
||||
if ( !server )
|
||||
return;
|
||||
server->documentRename( uri, pos, newName,
|
||||
[this]( const PluginIDType&, const LSPWorkspaceEdit& edit ) {
|
||||
applyWorkspaceEdit( edit, []( const auto& ) {} );
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientServerManager::run( const std::shared_ptr<TextDocument>& doc ) {
|
||||
mThreadPool->run( [&, doc]() { tryRunServer( doc ); } );
|
||||
}
|
||||
|
||||
@@ -92,6 +92,8 @@ class LSPClientServerManager {
|
||||
const LSPWorkspaceEdit& edit,
|
||||
const std::function<void( const LSPApplyWorkspaceEditResponse& res )>& resCb );
|
||||
|
||||
void renameSymbol( const URI& uri, const TextPosition& pos, const std::string& newName );
|
||||
|
||||
protected:
|
||||
friend class LSPClientServer;
|
||||
PluginManager* mPluginManager{ nullptr };
|
||||
|
||||
Reference in New Issue
Block a user