mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 01:56:31 +03:00
ecode: Implemented search document symbols in current document. Fixed a minor bug in log level configuration.
This commit is contained in:
@@ -5,15 +5,16 @@ namespace ecode {
|
||||
|
||||
class LSPSymbolInfoModel : public Model {
|
||||
public:
|
||||
static std::shared_ptr<LSPSymbolInfoModel>
|
||||
create( UISceneNode* uiSceneNode, const std::string& query,
|
||||
const std::vector<LSPSymbolInformation>& data ) {
|
||||
return std::make_shared<LSPSymbolInfoModel>( uiSceneNode, query, data );
|
||||
static std::shared_ptr<LSPSymbolInfoModel> create( UISceneNode* uiSceneNode,
|
||||
const std::string& query,
|
||||
const LSPSymbolInformationList& data,
|
||||
bool displayLine = false ) {
|
||||
return std::make_shared<LSPSymbolInfoModel>( uiSceneNode, query, data, displayLine );
|
||||
}
|
||||
|
||||
explicit LSPSymbolInfoModel( UISceneNode* uiSceneNode, const std::string& query,
|
||||
const std::vector<LSPSymbolInformation>& info ) :
|
||||
mUISceneNode( uiSceneNode ), mQuery( query ), mInfo( info ) {}
|
||||
const LSPSymbolInformationList& info, bool displayLine ) :
|
||||
mUISceneNode( uiSceneNode ), mQuery( query ), mInfo( info ), mDisplayLine( displayLine ) {}
|
||||
|
||||
size_t rowCount( const ModelIndex& ) const override { return mInfo.size(); };
|
||||
|
||||
@@ -26,8 +27,17 @@ class LSPSymbolInfoModel : public Model {
|
||||
switch ( index.column() ) {
|
||||
case 0:
|
||||
return Variant( mInfo[index.row()].name.c_str() );
|
||||
case 1:
|
||||
return Variant( mInfo[index.row()].url.getFSPath() );
|
||||
case 1: {
|
||||
if ( mDisplayLine ) {
|
||||
std::string detail( !mInfo[index.row()].detail.empty()
|
||||
? mInfo[index.row()].detail + " (" +
|
||||
mInfo[index.row()].range.toString() + ")"
|
||||
: mInfo[index.row()].range.toString() );
|
||||
return Variant( detail );
|
||||
} else {
|
||||
return Variant( mInfo[index.row()].url.getFSPath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ( role == ModelRole::Icon && index.column() == 0 ) {
|
||||
return mUISceneNode->findIcon(
|
||||
@@ -40,7 +50,7 @@ class LSPSymbolInfoModel : public Model {
|
||||
|
||||
void update() override { onModelUpdate(); }
|
||||
|
||||
const std::vector<LSPSymbolInformation>& getInfo() const { return mInfo; }
|
||||
const LSPSymbolInformationList& getInfo() const { return mInfo; }
|
||||
|
||||
LSPSymbolInformation at( const size_t& idx ) {
|
||||
eeASSERT( idx < mInfo.size() );
|
||||
@@ -49,7 +59,7 @@ class LSPSymbolInfoModel : public Model {
|
||||
|
||||
const std::string& getQuery() const { return mQuery; }
|
||||
|
||||
void append( const std::vector<LSPSymbolInformation>& res ) {
|
||||
void append( const LSPSymbolInformationList& res ) {
|
||||
mInfo.insert( mInfo.end(), res.begin(), res.end() );
|
||||
std::sort( mInfo.begin(), mInfo.end(),
|
||||
[]( const LSPSymbolInformation& l, const LSPSymbolInformation& r ) {
|
||||
@@ -60,8 +70,8 @@ class LSPSymbolInfoModel : public Model {
|
||||
|
||||
void setQuery( const std::string& query ) {
|
||||
if ( mQuery != query ) {
|
||||
mQuery = query;
|
||||
clear();
|
||||
mQuery = query;
|
||||
onModelUpdate();
|
||||
}
|
||||
}
|
||||
@@ -71,9 +81,30 @@ class LSPSymbolInfoModel : public Model {
|
||||
protected:
|
||||
UISceneNode* mUISceneNode{ nullptr };
|
||||
std::string mQuery;
|
||||
std::vector<LSPSymbolInformation> mInfo;
|
||||
LSPSymbolInformationList mInfo;
|
||||
bool mDisplayLine{ false };
|
||||
};
|
||||
|
||||
LSPSymbolInformationList fuzzyMatchTextDocumentSymbol( const LSPSymbolInformationList& list,
|
||||
const std::string& query,
|
||||
const size_t& limit ) {
|
||||
LSPSymbolInformationList nl;
|
||||
std::map<int, LSPSymbolInformation, std::greater<int>> matchesMap;
|
||||
|
||||
for ( const auto& l : list ) {
|
||||
int matchName = String::fuzzyMatch( l.name, query );
|
||||
matchesMap.insert( { matchName, l } );
|
||||
}
|
||||
|
||||
while ( matchesMap.size() > limit )
|
||||
matchesMap.erase( std::prev( matchesMap.end() ) );
|
||||
|
||||
for ( const auto& m : matchesMap )
|
||||
nl.emplace_back( std::move( m.second ) );
|
||||
|
||||
return nl;
|
||||
}
|
||||
|
||||
static int LOCATEBAR_MAX_VISIBLE_ITEMS = 18;
|
||||
static int LOCATEBAR_MAX_RESULTS = 100;
|
||||
|
||||
@@ -169,7 +200,8 @@ void UniversalLocator::goToLine() {
|
||||
}
|
||||
|
||||
static bool isCommand( const std::string& filename ) {
|
||||
return !filename.empty() && ( filename == "> " || filename == ": " || filename == "l " );
|
||||
return !filename.empty() &&
|
||||
( filename == "> " || filename == ": " || filename == "l " || filename == ". " );
|
||||
}
|
||||
|
||||
void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInput ) {
|
||||
@@ -202,6 +234,8 @@ void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locat
|
||||
showCommandPalette();
|
||||
} else if ( !txt.empty() && mLocateInput->getText()[0] == ':' ) {
|
||||
showWorkspaceSymbol();
|
||||
} else if ( String::startsWith( txt, ". " ) ) {
|
||||
showDocumentSymbol();
|
||||
} else {
|
||||
showLocateTable();
|
||||
if ( !mApp->isDirTreeReady() )
|
||||
@@ -259,7 +293,7 @@ void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locat
|
||||
Variant vPath( modelEvent->getModel()->data(
|
||||
modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 1 ),
|
||||
ModelRole::Display ) );
|
||||
if ( vPath.isValid() ) {
|
||||
if ( vPath.isValid() && !String::startsWith( mLocateInput->getText(), ". " ) ) {
|
||||
std::string path( vPath.is( Variant::Type::cstr ) ? vPath.asCStr()
|
||||
: vPath.asStdString() );
|
||||
if ( path.empty() )
|
||||
@@ -288,6 +322,22 @@ void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locat
|
||||
}
|
||||
}
|
||||
mLocateBarLayout->execute( "close-locatebar" );
|
||||
} else {
|
||||
Variant rangeStr( modelEvent->getModel()->data(
|
||||
modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 1 ),
|
||||
ModelRole::Custom ) );
|
||||
auto range = rangeStr.isValid()
|
||||
? TextRange::fromString( rangeStr.asStdString() )
|
||||
: TextRange();
|
||||
if ( !range.isValid() )
|
||||
return;
|
||||
UITab* tab = mSplitter->isDocumentOpen( URI( mCurDocURI ), true );
|
||||
if ( tab ) {
|
||||
tab->getTabWidget()->setTabSelected( tab );
|
||||
UICodeEditor* editor = tab->getOwnedWidget()->asType<UICodeEditor>();
|
||||
editor->goToLine( range.start() );
|
||||
mLocateBarLayout->execute( "close-locatebar" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,21 +420,42 @@ void UniversalLocator::showWorkspaceSymbol() {
|
||||
updateLocateBar();
|
||||
}
|
||||
|
||||
void UniversalLocator::showDocumentSymbol() {
|
||||
showBar();
|
||||
|
||||
if ( mLocateInput->getText().empty() || mLocateInput->getText()[0] != '.' )
|
||||
mLocateInput->setText( ". " );
|
||||
|
||||
requestDocumentSymbol();
|
||||
updateLocateBar();
|
||||
}
|
||||
|
||||
void UniversalLocator::onCodeEditorFocusChange( UICodeEditor* editor ) {
|
||||
if ( !mLocateTable || !mLocateTable->isVisible() )
|
||||
return;
|
||||
|
||||
if ( String::startsWith( mLocateInput->getText(), ". " ) &&
|
||||
editor->getDocument().getURI().toString() != mCurDocURI )
|
||||
showDocumentSymbol();
|
||||
}
|
||||
|
||||
std::shared_ptr<LSPSymbolInfoModel> UniversalLocator::emptyModel( const String& defTxt,
|
||||
const std::string& query ) {
|
||||
LSPSymbolInformation info;
|
||||
info.name = defTxt.toUtf8();
|
||||
info.url = "";
|
||||
return LSPSymbolInfoModel::create( mUISceneNode, query, { info } );
|
||||
}
|
||||
|
||||
void UniversalLocator::requestWorkspaceSymbol() {
|
||||
if ( mLocateInput->getText().empty() )
|
||||
return;
|
||||
auto txt( mLocateInput->getText().substr( 1 ).trim() );
|
||||
if ( mWorkspaceSymbolQuery != txt.toUtf8() || mWorkspaceSymbolQuery.empty() ) {
|
||||
mWorkspaceSymbolQuery = txt.toUtf8();
|
||||
if ( mWorkspaceSymbolModel ) {
|
||||
mWorkspaceSymbolModel->setQuery( mWorkspaceSymbolQuery );
|
||||
} else {
|
||||
if ( !mWorkspaceSymbolModel ) {
|
||||
auto defTxt = mUISceneNode->i18n( "no_running_lsp_server", "No running LSP server" );
|
||||
LSPSymbolInformation info;
|
||||
info.name = defTxt.toUtf8();
|
||||
info.url = "";
|
||||
mWorkspaceSymbolModel = LSPSymbolInfoModel::create( mApp->getUISceneNode(),
|
||||
mWorkspaceSymbolQuery, { info } );
|
||||
mWorkspaceSymbolModel = emptyModel( defTxt, mWorkspaceSymbolQuery );
|
||||
}
|
||||
mLocateTable->setModel( mWorkspaceSymbolModel );
|
||||
|
||||
@@ -394,26 +465,119 @@ void UniversalLocator::requestWorkspaceSymbol() {
|
||||
}
|
||||
}
|
||||
|
||||
void UniversalLocator::updateWorkspaceSymbol( const std::vector<LSPSymbolInformation>& res ) {
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
|
||||
void UniversalLocator::updateWorkspaceSymbol( const LSPSymbolInformationList& res ) {
|
||||
mUISceneNode->runOnMainThread( [&, res] {
|
||||
if ( !mWorkspaceSymbolModel ) {
|
||||
mWorkspaceSymbolModel =
|
||||
LSPSymbolInfoModel::create( mApp->getUISceneNode(), mWorkspaceSymbolQuery, res );
|
||||
} else {
|
||||
mWorkspaceSymbolModel->setQuery( mWorkspaceSymbolQuery );
|
||||
mWorkspaceSymbolModel->append( res );
|
||||
}
|
||||
mLocateTable->setModel( mWorkspaceSymbolModel );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} );
|
||||
}
|
||||
|
||||
void UniversalLocator::requestDocumentSymbol() {
|
||||
if ( mLocateInput->getText().empty() )
|
||||
return;
|
||||
auto txt( mLocateInput->getText().substr( 1 ).trim() );
|
||||
bool needsUpdate = false;
|
||||
if ( txt != mCurDocQuery || getCurDocURI() != mCurDocURI ) {
|
||||
mCurDocQuery = txt;
|
||||
mCurDocURI = getCurDocURI();
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
|
||||
if ( mSplitter->curEditorIsNotNull() ) {
|
||||
if ( needsUpdate ) {
|
||||
mTextDocumentSymbolModel = emptyModel(
|
||||
mUISceneNode->i18n( "no_running_lsp_server", "No running LSP server" ) );
|
||||
json j;
|
||||
j["uri"] = mCurDocURI = getCurDocURI();
|
||||
mApp->getPluginManager()->sendRequest( PluginMessageType::TextDocumentFlattenSymbol,
|
||||
PluginMessageFormat::JSON, &j );
|
||||
} else {
|
||||
if ( !mTextDocumentSymbolModel ) {
|
||||
mTextDocumentSymbolModel = emptyModel(
|
||||
mUISceneNode->i18n( "no_running_lsp_server", "No running LSP server" ) );
|
||||
}
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
}
|
||||
} else {
|
||||
mTextDocumentSymbolModel =
|
||||
emptyModel( mUISceneNode->i18n( "no_open_document", "No open document" ) );
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
}
|
||||
}
|
||||
|
||||
void UniversalLocator::updateDocumentSymbol( const LSPSymbolInformationList& res ) {
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
|
||||
if ( mCurDocQuery.empty() ) {
|
||||
mTextDocumentSymbolModel =
|
||||
LSPSymbolInfoModel::create( mApp->getUISceneNode(), mCurDocQuery, res, true );
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} else {
|
||||
asyncFuzzyMatchTextDocumentSymbol( res, mCurDocQuery, 100, [&]( const auto model ) {
|
||||
mTextDocumentSymbolModel = model;
|
||||
mUISceneNode->runOnMainThread( [&] {
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} );
|
||||
} );
|
||||
}
|
||||
#else
|
||||
mLocateTable->setModel( mWorkspaceSymbolModel );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
mUISceneNode->runOnMainThread( [&, res] {
|
||||
if ( mCurDocQuery.empty() ) {
|
||||
mTextDocumentSymbolModel =
|
||||
LSPSymbolInfoModel::create( mApp->getUISceneNode(), mCurDocQuery, res, true );
|
||||
} else {
|
||||
mTextDocumentSymbolModel = LSPSymbolInfoModel::create(
|
||||
mApp->getUISceneNode(), mCurDocQuery,
|
||||
fuzzyMatchTextDocumentSymbol( res, mCurDocQuery, 100 ), true );
|
||||
}
|
||||
mLocateTable->setModel( mTextDocumentSymbolModel );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} );
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string UniversalLocator::getCurDocURI() {
|
||||
return mSplitter->curEditorIsNotNull()
|
||||
? mSplitter->getCurEditor()->getDocument().getURI().toString()
|
||||
: "";
|
||||
}
|
||||
|
||||
PluginRequestHandle UniversalLocator::processResponse( const PluginMessage& msg ) {
|
||||
if ( msg.isResponse() && msg.type == PluginMessageType::WorkspaceSymbol &&
|
||||
msg.format == PluginMessageFormat::SymbolInformation ) {
|
||||
updateWorkspaceSymbol( msg.asSymbolInformation() );
|
||||
} else if ( msg.isResponse() && msg.type == PluginMessageType::TextDocumentFlattenSymbol &&
|
||||
msg.format == PluginMessageFormat::SymbolInformation ) {
|
||||
if ( String::startsWith( mLocateInput->getText(), ". " ) && msg.responseID.isString() &&
|
||||
mCurDocURI == msg.responseID.asString() )
|
||||
updateDocumentSymbol( msg.asSymbolInformation() );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void UniversalLocator::asyncFuzzyMatchTextDocumentSymbol(
|
||||
const LSPSymbolInformationList& list, const std::string& query, const size_t& limit,
|
||||
std::function<void( std::shared_ptr<LSPSymbolInfoModel> )> cb ) {
|
||||
mApp->getThreadPool()->run( [this, list, query, limit, cb] {
|
||||
cb( LSPSymbolInfoModel::create(
|
||||
mUISceneNode, query, fuzzyMatchTextDocumentSymbol( list, query, limit ), true ) );
|
||||
} );
|
||||
}
|
||||
|
||||
std::vector<ProjectDirectoryTree::CommandInfo> UniversalLocator::getLocatorCommands() const {
|
||||
std::vector<ProjectDirectoryTree::CommandInfo> vec;
|
||||
UIIcon* icon = mUISceneNode->findIcon( "chevron-right" );
|
||||
@@ -424,6 +588,10 @@ std::vector<ProjectDirectoryTree::CommandInfo> UniversalLocator::getLocatorComma
|
||||
{ ": ",
|
||||
mUISceneNode->i18n( "search_for_workspace_symbols", "Search for Workspace Symbols" ),
|
||||
icon } );
|
||||
vec.push_back( { ". ",
|
||||
mUISceneNode->i18n( "search_for_document_symbols",
|
||||
"Search for Symbols in Current Document" ),
|
||||
icon } );
|
||||
vec.push_back(
|
||||
{ "l ",
|
||||
mUISceneNode->i18n( "go_to_line_in_current_document", "Go To Line in Current Document" ),
|
||||
@@ -431,11 +599,4 @@ std::vector<ProjectDirectoryTree::CommandInfo> UniversalLocator::getLocatorComma
|
||||
return vec;
|
||||
}
|
||||
|
||||
PluginRequestHandle UniversalLocator::processResponse( const PluginMessage& msg ) {
|
||||
if ( msg.isResponse() && msg.type == PluginMessageType::WorkspaceSymbol ) {
|
||||
updateWorkspaceSymbol( msg.asSymbolInformation() );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
Reference in New Issue
Block a user