ecode: Implemented LSP textDocument/references ("Find References to Symbol Under Cursor").

This commit is contained in:
Martín Lucas Golini
2023-02-05 03:26:13 -03:00
parent 3aaf5dc48a
commit ecba3fa9aa
14 changed files with 250 additions and 87 deletions

View File

@@ -832,6 +832,12 @@ class EE_API String {
/** Replace all occurrences of the search string with the replacement string. */
void replaceAll( const String& that, const String& with );
void pop_back();
const StringBaseType& front() const;
const StringBaseType& back() const;
private:
friend EE_API bool operator==( const String& left, const String& right );
friend EE_API bool operator<( const String& left, const String& right );

View File

@@ -711,6 +711,18 @@ void String::replaceAll( const String& that, const String& with ) {
String::replaceAll( *this, that, with );
}
void String::pop_back() {
mString.pop_back();
}
const String::StringBaseType& String::front() const {
return mString.front();
}
const String::StringBaseType& String::back() const {
return mString.back();
}
void String::replace( std::string& target, const std::string& that, const std::string& with ) {
std::size_t start_pos = target.find( that );
if ( start_pos == std::string::npos )

View File

@@ -1012,16 +1012,19 @@ bool UICodeEditor::onCreateContextMenu( const Vector2i& position, const Uint32&
} );
Vector2f pos( position.asFloat() );
menu->nodeToWorldTranslation( pos );
UIMenu::findBestMenuPos( pos, menu );
menu->setPixelsPosition( pos );
menu->show();
runOnMainThread( [this, menu, pos]() {
Vector2f npos( pos );
menu->nodeToWorldTranslation( npos );
UIMenu::findBestMenuPos( npos, menu );
menu->setPixelsPosition( npos );
menu->show();
mCurrentMenu = menu;
} );
menu->addEventListener( Event::OnMenuHide, [&]( const Event* ) {
if ( !isClosing() )
setFocus();
} );
menu->addEventListener( Event::OnClose, [&]( const Event* ) { mCurrentMenu = nullptr; } );
mCurrentMenu = menu;
return true;
}
@@ -1111,6 +1114,8 @@ Uint32 UICodeEditor::onMouseDown( const Vector2i& position, const Uint32& flags
} else {
mDoc->setSelection( resolveScreenPosition( position.asFloat() ) );
}
} else {
mDoc->setSelection( resolveScreenPosition( position.asFloat() ) );
}
}
return UIWidget::onMouseDown( position, flags );

View File

@@ -7,7 +7,11 @@ static int LOCATEBAR_MAX_VISIBLE_ITEMS = 18;
GlobalSearchController::GlobalSearchController( UICodeEditorSplitter* editorSplitter,
UISceneNode* sceneNode, App* app ) :
mEditorSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ) {}
mSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ) {
mApp->getPluginManager()->subscribeMessages(
"GlobalSearchController",
[&]( const PluginMessage& msg ) -> PluginRequestHandle { return processMessage( msg ); } );
}
static bool replaceInFile( const std::string& path, const std::string& replaceText,
const std::vector<std::pair<Int64, Int64>>& replacements ) {
@@ -30,8 +34,13 @@ static bool replaceInFile( const std::string& path, const std::string& replaceTe
size_t GlobalSearchController::replaceInFiles( const std::string& replaceText,
std::shared_ptr<ProjectSearch::ResultModel> model ) {
const ProjectSearch::Result& res = model.get()->getResult();
size_t count = 0;
if ( model->isResultFromSymbolReference() ) {
// TODO Implement replacement from result from symbol reference
return count;
}
const ProjectSearch::Result& res = model.get()->getResult();
for ( const auto& fileResult : res ) {
std::vector<std::pair<Int64, Int64>> replacements;
@@ -133,8 +142,8 @@ void GlobalSearchController::initGlobalSearchBar(
} );
mGlobalSearchBarLayout->setCommand( "close-global-searchbar", [&] {
hideGlobalSearchBar();
if ( mEditorSplitter->getCurWidget() )
mEditorSplitter->getCurWidget()->setFocus();
if ( mSplitter->getCurWidget() )
mSplitter->getCurWidget()->setFocus();
} );
mGlobalSearchBarLayout->setCommand( "expand-all", [&] {
mGlobalSearchTree->expandAll();
@@ -250,9 +259,18 @@ void GlobalSearchController::initGlobalSearchBar(
replaceInput->getDocument().selectAll();
return;
}
doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(),
wholeWordChk->isChecked(), luaPatternChk->isChecked(),
escapeSequenceChk->isChecked(), true );
// TODO Implement replacement from result from symbol reference
/*if ( mGlobalSearchHistory.back().second->isResultFromSymbolReference() ) {
mGlobalSearchTreeReplace->setModel( mGlobalSearchHistory.back().second );
showGlobalSearch( true );
updateGlobalSearchBarResults( mGlobalSearchHistory.back().first,
mGlobalSearchHistory.back().second, true, false );
} else*/ {
doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(),
wholeWordChk->isChecked(), luaPatternChk->isChecked(),
escapeSequenceChk->isChecked(), true );
}
} );
mGlobalSearchBarLayout->setCommand( "replace-in-files", [&, replaceInput, escapeSequenceChk] {
auto listBox = mGlobalSearchHistoryList->getListBox();
@@ -270,9 +288,9 @@ void GlobalSearchController::initGlobalSearchBar(
}
} );
mGlobalSearchTreeSearch =
UITreeViewGlobalSearch::New( mEditorSplitter->getCurrentColorScheme(), false );
UITreeViewGlobalSearch::New( mSplitter->getCurrentColorScheme(), false );
mGlobalSearchTreeReplace =
UITreeViewGlobalSearch::New( mEditorSplitter->getCurrentColorScheme(), true );
UITreeViewGlobalSearch::New( mSplitter->getCurrentColorScheme(), true );
initGlobalSearchTree( mGlobalSearchTreeSearch );
initGlobalSearchTree( mGlobalSearchTreeReplace );
mGlobalSearchTreeReplace->addEventListener( Event::KeyDown, [&]( const Event* event ) {
@@ -295,9 +313,9 @@ void GlobalSearchController::showGlobalSearch( bool searchReplace ) {
mGlobalSearchInput->setFocus();
mGlobalSearchLayout->setVisible( true );
UICheckBox* escapeSequenceChk = mGlobalSearchBarLayout->find<UICheckBox>( "escape_sequence" );
if ( mEditorSplitter->curEditorExistsAndFocused() &&
mEditorSplitter->getCurEditor()->getDocument().hasSelection() ) {
auto& doc = mEditorSplitter->getCurEditor()->getDocument();
if ( mSplitter->curEditorExistsAndFocused() &&
mSplitter->getCurEditor()->getDocument().hasSelection() ) {
auto& doc = mSplitter->getCurEditor()->getDocument();
String text = doc.getSelectedText();
if ( !doc.getSelection().inSameLine() ) {
text.escape();
@@ -405,6 +423,40 @@ void GlobalSearchController::updateGlobalSearchBarResults(
}
}
void GlobalSearchController::updateGlobalSearchHistory(
std::shared_ptr<ProjectSearch::ResultModel> model, const std::string& search,
bool searchReplace, bool searchAgain, bool escapeSequence ) {
auto listBox = mGlobalSearchHistoryList->getListBox();
if ( !searchAgain ) {
mGlobalSearchHistory.push_back( std::make_pair( search, model ) );
if ( mGlobalSearchHistory.size() > 10 )
mGlobalSearchHistory.pop_front();
std::vector<String> items;
for ( auto item = mGlobalSearchHistory.rbegin(); item != mGlobalSearchHistory.rend();
item++ ) {
items.push_back( item->first );
}
listBox->clear();
listBox->addListBoxItems( items );
if ( mGlobalSearchHistoryOnItemSelectedCb )
mGlobalSearchHistoryList->removeEventListener( mGlobalSearchHistoryOnItemSelectedCb );
listBox->setSelected( 0 );
mGlobalSearchHistoryOnItemSelectedCb = mGlobalSearchHistoryList->addEventListener(
Event::OnItemSelected, [&, searchReplace]( const Event* ) {
auto idx = mGlobalSearchHistoryList->getListBox()->getItemSelectedIndex();
auto idxItem = mGlobalSearchHistory.at( mGlobalSearchHistory.size() - 1 - idx );
updateGlobalSearchBarResults( idxItem.first, idxItem.second, searchReplace,
escapeSequence );
} );
} else if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) {
mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 - listBox->getItemSelectedIndex()]
.second = model;
}
}
void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bool wholeWord,
bool luaPattern, bool escapeSequence,
bool searchReplace, bool searchAgain ) {
@@ -439,41 +491,8 @@ void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bo
mUISceneNode->runOnMainThread( [&, loader, res, search, searchReplace, searchAgain,
escapeSequence] {
auto model = ProjectSearch::asModel( res );
auto listBox = mGlobalSearchHistoryList->getListBox();
if ( !searchAgain ) {
mGlobalSearchHistory.push_back( std::make_pair( search, model ) );
if ( mGlobalSearchHistory.size() > 10 )
mGlobalSearchHistory.pop_front();
std::vector<String> items;
for ( auto item = mGlobalSearchHistory.rbegin();
item != mGlobalSearchHistory.rend(); item++ ) {
items.push_back( item->first );
}
listBox->clear();
listBox->addListBoxItems( items );
if ( mGlobalSearchHistoryOnItemSelectedCb )
mGlobalSearchHistoryList->removeEventListener(
mGlobalSearchHistoryOnItemSelectedCb );
listBox->setSelected( 0 );
mGlobalSearchHistoryOnItemSelectedCb =
mGlobalSearchHistoryList->addEventListener(
Event::OnItemSelected, [&, searchReplace]( const Event* ) {
auto idx = mGlobalSearchHistoryList->getListBox()
->getItemSelectedIndex();
auto idxItem = mGlobalSearchHistory.at(
mGlobalSearchHistory.size() - 1 - idx );
updateGlobalSearchBarResults( idxItem.first, idxItem.second,
searchReplace, escapeSequence );
} );
} else if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) {
mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 -
listBox->getItemSelectedIndex()]
.second = model;
}
updateGlobalSearchHistory( model, search, searchReplace, searchAgain,
escapeSequence );
updateGlobalSearchBarResults( search, model, searchReplace, escapeSequence );
loader->setVisible( false );
loader->close();
@@ -486,11 +505,11 @@ void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bo
}
void GlobalSearchController::onLoadDone( const Variant& lineNum, const Variant& colNum ) {
if ( mEditorSplitter->curEditorExistsAndFocused() && lineNum.isValid() && colNum.isValid() &&
if ( mSplitter->curEditorExistsAndFocused() && lineNum.isValid() && colNum.isValid() &&
lineNum.is( Variant::Type::Int64 ) && colNum.is( Variant::Type::Int64 ) ) {
TextPosition pos{ lineNum.asInt64(), colNum.asInt64() };
mEditorSplitter->getCurEditor()->getDocument().setSelection( pos );
mEditorSplitter->getCurEditor()->goToLine( pos );
mSplitter->getCurEditor()->getDocument().setSelection( pos );
mSplitter->getCurEditor()->goToLine( pos );
hideGlobalSearchBar();
}
}
@@ -529,7 +548,7 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc
ModelRole::Custom ) );
if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) {
std::string path( vPath.asCStr() );
UITab* tab = mEditorSplitter->isDocumentOpen( path );
UITab* tab = mSplitter->isDocumentOpen( path );
Variant lineNum(
model->data( model->index( modelEvent->getModelIndex().row(),
ProjectSearch::ResultModel::FileOrPosition,
@@ -556,4 +575,41 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc
} );
}
PluginRequestHandle GlobalSearchController::processMessage( const PluginMessage& msg ) {
if ( msg.type != PluginMessageType::SymbolReference || !msg.isBroadcast() )
return {};
const ProjectSearch::Result& res = msg.asProjectSearchResult();
if ( res.empty() )
return {};
auto model = ProjectSearch::asModel( res );
model->removeLastNewLineCharacter();
model->setResultFromSymbolReference( true );
ProjectSearch::ResultData::Result sample;
for ( const auto& r : res ) {
if ( !r.results.empty() ) {
sample = r.results.front();
break;
}
}
if ( sample.line.empty() )
return {};
if ( sample.position.end().column() - sample.position.start().column() <= 0 )
return {};
auto search =
sample.line.substr( sample.position.start().column(),
sample.position.end().column() - sample.position.start().column() );
showGlobalSearch( false );
mGlobalSearchInput->setText( search );
updateGlobalSearchHistory( model, search, false, false, false );
updateGlobalSearchBarResults( search, model, false, false );
return {};
}
} // namespace ecode

View File

@@ -2,6 +2,7 @@
#define ECODE_GLOBALSEARCHCONTROLLER_HPP
#include "appconfig.hpp"
#include "plugins/pluginmanager.hpp"
#include "projectsearch.hpp"
#include <eepp/ee.hpp>
@@ -63,7 +64,7 @@ class GlobalSearchController {
GlobalSearchBarConfig getGlobalSearchBarConfig() const;
protected:
UICodeEditorSplitter* mEditorSplitter{ nullptr };
UICodeEditorSplitter* mSplitter{ nullptr };
UISceneNode* mUISceneNode{ nullptr };
App* mApp{ nullptr };
@@ -79,6 +80,12 @@ class GlobalSearchController {
mGlobalSearchHistory;
void onLoadDone( const Variant& lineNum, const Variant& colNum );
PluginRequestHandle processMessage( const PluginMessage& msg );
void updateGlobalSearchHistory( std::shared_ptr<ProjectSearch::ResultModel> model,
const std::string& search, bool searchReplace, bool searchAgain,
bool escapeSequence );
};
} // namespace ecode

View File

@@ -306,7 +306,8 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
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-switch-header-source", "lsp-symbol-info",
"lsp-symbol-references" };
for ( const auto& key : list ) {
if ( kb.contains( key ) ) {
if ( !kb[key].empty() )
@@ -442,31 +443,36 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) {
}
if ( editor->hasDocument() ) {
editor->getDocument().setCommand( "lsp-go-to-definition", [&, editor]() {
auto& doc = editor->getDocument();
doc.setCommand( "lsp-go-to-definition", [&, editor]() {
mClientManager.getAndGoToLocation( editor->getDocumentRef(),
"textDocument/definition" );
} );
editor->getDocument().setCommand( "lsp-go-to-declaration", [&, editor]() {
doc.setCommand( "lsp-go-to-declaration", [&, editor]() {
mClientManager.getAndGoToLocation( editor->getDocumentRef(),
"textDocument/declaration" );
} );
editor->getDocument().setCommand( "lsp-go-to-implementation", [&, editor]() {
doc.setCommand( "lsp-go-to-implementation", [&, editor]() {
mClientManager.getAndGoToLocation( editor->getDocumentRef(),
"textDocument/implementation" );
} );
editor->getDocument().setCommand( "lsp-go-to-type-definition", [&, editor]() {
doc.setCommand( "lsp-go-to-type-definition", [&, editor]() {
mClientManager.getAndGoToLocation( editor->getDocumentRef(),
"textDocument/typeDefinition" );
} );
editor->getDocument().setCommand( "lsp-switch-header-source",
[&, editor]() { switchSourceHeader( editor ); } );
doc.setCommand( "lsp-switch-header-source",
[&, editor]() { switchSourceHeader( editor ); } );
editor->getDocument().setCommand( "lsp-symbol-info",
[&, editor]() { getSymbolInfo( editor ); } );
doc.setCommand( "lsp-symbol-info", [&, editor]() { getSymbolInfo( editor ); } );
doc.setCommand( "lsp-symbol-references", [&, editor] {
mClientManager.getSymbolReferences( editor->getDocumentRef() );
} );
}
std::vector<Uint32> listeners;
@@ -573,6 +579,9 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me
if ( cap.implementationProvider )
addFn( "lsp-go-to-implementation", "Go To Implementation" );
if ( cap.referencesProvider )
addFn( "lsp-symbol-references", "Find References to Symbol Under Cursor" );
if ( server->getDefinition().language == "cpp" || server->getDefinition().language == "c" )
addFn( "lsp-switch-header-source", "Switch Header/Source" );

View File

@@ -168,12 +168,10 @@ static LSPLocation parseLocationLink( const json& loc ) {
static std::vector<LSPLocation> parseDocumentLocation( const json& result ) {
std::vector<LSPLocation> ret;
if ( result.is_array() ) {
const auto& locs = result;
for ( const auto& def : locs ) {
const auto& ob = def;
ret.push_back( parseLocation( ob ) );
for ( const auto& def : result ) {
ret.push_back( parseLocation( def ) );
if ( ret.back().uri.empty() )
ret.back() = parseLocationLink( ob );
ret.back() = parseLocationLink( def );
}
} else if ( result.is_object() ) {
ret.push_back( parseLocation( result ) );
@@ -197,7 +195,9 @@ static json textDocumentPositionParams( const URI& document, TextPosition pos )
static json referenceParams( const URI& document, TextPosition pos, bool decl ) {
auto params = textDocumentPositionParams( document, pos );
params["context"] = json{ { "includeDeclaration", decl } };
json refCtx;
refCtx["includeDeclaration"] = decl;
params["context"] = refCtx;
return params;
}
@@ -301,6 +301,7 @@ static void fromJson( LSPServerCapabilities& caps, const json& json ) {
caps.documentSymbolProvider = toBoolOrObject( json, "documentSymbolProvider" );
caps.documentHighlightProvider = toBoolOrObject( json, "documentHighlightProvider" );
caps.documentFormattingProvider = toBoolOrObject( json, "documentFormattingProvider" );
caps.workspaceSymbolProvider = toBoolOrObject( json, "workspaceSymbolProvider" );
if ( json.contains( "documentRangeFormattingProvider" ) )
caps.documentRangeFormattingProvider =
toBoolOrObject( json, "documentRangeFormattingProvider" );

View File

@@ -149,6 +149,9 @@ class LSPClientServer {
LSPRequestHandle documentReferences( const URI& document, const TextPosition& pos, bool decl,
const JsonReplyHandler& h );
LSPRequestHandle documentReferences( const URI& document, const TextPosition& pos, bool decl,
const LocationHandler& h );
LSPRequestHandle documentCompletion( const URI& document, const TextPosition& pos,
const JsonReplyHandler& h );
@@ -187,10 +190,6 @@ class LSPClientServer {
void removeDoc( TextDocument* doc );
LSPClientServer::LSPRequestHandle documentReferences( const URI& document,
const TextPosition& pos, bool decl,
const LocationHandler& h );
protected:
LSPClientServerManager* mManager{ nullptr };
String::HashType mId;

View File

@@ -1,4 +1,5 @@
#include "lspclientservermanager.hpp"
#include "../../projectsearch.hpp"
#include "lspclientplugin.hpp"
#include <algorithm>
#include <eepp/system/filesystem.hpp>
@@ -237,6 +238,47 @@ void LSPClientServerManager::setLSPDecayTime( const Time& lSPDecayTime ) {
mLSPDecayTime = lSPDecayTime;
}
void LSPClientServerManager::sendSymbolReferenceBroadcast( const std::vector<LSPLocation>& resp ) {
if ( resp.empty() )
return;
std::map<std::string, ProjectSearch::ResultData> res;
for ( auto& r : resp ) {
auto& rd = res[r.uri.getPath()];
if ( rd.file.empty() )
rd.file = r.uri.getPath();
auto curDoc = mPluginManager->getSplitter()->findDocFromPath( r.uri.getPath() );
if ( !curDoc )
continue;
ProjectSearch::ResultData::Result rs( curDoc->line( r.range.start().line() ).getText(),
r.range, -1, -1 );
rd.results.emplace_back( std::move( rs ) );
}
ProjectSearch::Result result;
for ( auto& r : res ) {
if ( !r.second.results.empty() )
result.emplace_back( std::move( r.second ) );
}
mPluginManager->sendBroadcast( PluginMessageType::SymbolReference,
PluginMessageFormat::ProjectSearchResult, &result );
}
void LSPClientServerManager::getSymbolReferences( std::shared_ptr<TextDocument> doc ) {
auto* server = getOneLSPClientServer( doc );
if ( !server )
return;
server->documentReferences(
doc->getURI(), doc->getSelection().start(), true,
[this]( const PluginIDType&, const std::vector<LSPLocation>& resp ) {
sendSymbolReferenceBroadcast( resp );
} );
}
void LSPClientServerManager::didChangeWorkspaceFolders( const std::string& folder ) {
mLSPWorkspaceFolder = { "file://" + folder, FileSystem::fileNameFromPath( folder ) };
Lock l( mClientsMutex );

View File

@@ -64,6 +64,8 @@ class LSPClientServerManager {
void setLSPDecayTime( const Time& lSPDecayTime );
void getSymbolReferences( std::shared_ptr<TextDocument> doc );
protected:
friend class LSPClientServer;
PluginManager* mPluginManager{ nullptr };
@@ -89,6 +91,8 @@ class LSPClientServerManager {
void closeLSPServer( const String::HashType& id );
void goToLocation( const LSPLocation& loc );
void sendSymbolReferenceBroadcast( const std::vector<LSPLocation>& resp );
};
} // namespace ecode

View File

@@ -101,6 +101,7 @@ struct LSPServerCapabilities {
bool documentHighlightProvider = false;
bool documentFormattingProvider = false;
bool documentRangeFormattingProvider = false;
bool workspaceSymbolProvider = false;
LSPDocumentOnTypeFormattingOptions documentOnTypeFormattingProvider;
bool renameProvider = false;
// CodeActionOptions not useful/considered at present

View File

@@ -1,6 +1,7 @@
#ifndef ECODE_PLUGINMANAGER_HPP
#define ECODE_PLUGINMANAGER_HPP
#include "../projectsearch.hpp"
#include "lsp/lspprotocol.hpp"
#include <eepp/ui/models/model.hpp>
#include <eepp/ui/tools/uicodeeditorsplitter.hpp>
@@ -68,6 +69,7 @@ enum class PluginMessageType {
CancelRequest, // Cancel a request ID
FindAndOpenClosestURI, // Request a component to find and open the closest path from an URI
DocumentFormatting, // Request the LSP Server to format a document
SymbolReference, // Request the LSP Server to find a symbol reference in the project
Undefined
};
@@ -77,7 +79,7 @@ enum class PluginMessageFormat {
CodeCompletion,
LanguageServerCapabilities,
SignatureHelp,
DocumentFormatting
ProjectSearchResult
};
class PluginIDType {
@@ -153,6 +155,10 @@ struct PluginMessage {
return *static_cast<const LSPSignatureHelp*>( data );
}
const ProjectSearch::Result& asProjectSearchResult() const {
return *static_cast<const ProjectSearch::Result*>( data );
}
const PluginIDType& asPluginID() const { return *static_cast<const PluginIDType*>( data ); }
bool isResponse() const { return -1 != responseID && 0 != responseID; }

View File

@@ -29,8 +29,8 @@ static String textLine( const std::string& fileText, const size_t& fromPos, size
nlStartPtr++;
while ( ++endPtr && *endPtr != '\0' && *endPtr != '\n' ) {
}
relCol = String::utf8Length(
fileText.substr( nlStartPtr - stringStartPtr, startPtr - nlStartPtr ) );
relCol =
String::utf8Length( fileText.substr( nlStartPtr - stringStartPtr, startPtr - nlStartPtr ) );
// if the line to substract is massive we only get the fist kilobyte of that line, since the
// line is only shared for visual aid.
return fileText.substr( nlStartPtr - stringStartPtr,
@@ -65,12 +65,11 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo
totNl += countNewLines( fileText, lSearchRes, searchRes );
String str(
textLine( caseSensitive ? fileText : fileTextOriginal, searchRes, relCol ) );
res.push_back(
{ str,
{ { (Int64)totNl, (Int64)relCol },
{ (Int64)totNl, (Int64)( relCol + String::utf8Length( text ) ) } },
searchRes,
static_cast<Int64>( searchRes + text.size() ) } );
res.push_back( { str,
{ { (Int64)totNl, (Int64)relCol },
{ (Int64)totNl, (Int64)( relCol + String::utf8Length( text ) ) } },
searchRes,
static_cast<Int64>( searchRes + text.size() ) } );
lSearchRes = searchRes;
searchRes += text.size();
}
@@ -185,4 +184,12 @@ void ProjectSearch::find( const std::vector<std::string> files, std::string stri
}
}
void ProjectSearch::ResultModel::removeLastNewLineCharacter() {
for ( auto& r : mResult ) {
for ( auto& r2 : r.results )
if ( !r2.line.empty() && r2.line.back() == '\n' )
r2.line.pop_back();
}
}
} // namespace ecode

View File

@@ -22,10 +22,11 @@ class ProjectSearch {
struct Result {
Result( const String& line, const TextRange& pos, Int64 s, Int64 e ) :
line( line ), position( pos ), start( s ), end( e ) {}
Result() {}
String line;
TextRange position;
Int64 start;
Int64 end;
Int64 start{ 0 };
Int64 end{ 0 };
bool selected{ true };
};
std::string file;
@@ -185,8 +186,15 @@ class ProjectSearch {
const Result& getResult() const { return mResult; }
void removeLastNewLineCharacter();
void setResultFromSymbolReference( bool ref ) { mResultFromSymbolReference = ref; }
bool isResultFromSymbolReference() const { return mResultFromSymbolReference; }
protected:
Result mResult;
bool mResultFromSymbolReference{ false };
};
static std::shared_ptr<ResultModel> asModel( const Result& result ) {