ecode: Implemented search document symbols in current document. Fixed a minor bug in log level configuration.

This commit is contained in:
Martín Lucas Golini
2023-03-01 23:04:15 -03:00
parent 202e044f8a
commit 323c3ebc01
15 changed files with 552 additions and 83 deletions

View File

@@ -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