Find/Replace improvements.

Windows build fix.
ecode: Minor fix in lspclient.json.
Minor fix in features health.
This commit is contained in:
Martín Lucas Golini
2023-03-10 20:08:15 -03:00
parent 5aef110bda
commit f7faa6240e
13 changed files with 125 additions and 71 deletions

View File

@@ -199,7 +199,7 @@
{
"language": "haskell",
"name": "haskell-language-server",
"url": "https://github.com/haskell/haskell-language-server --lsp",
"url": "https://github.com/haskell/haskell-language-server",
"command": "haskell-language-server-wrapper",
"file_patterns": ["%.hs$"],
"rootIndicationFileNames": ["%.cabal$", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml"]

View File

@@ -347,18 +347,16 @@ class EE_API TextDocument {
bool removeCommand( const std::string& command );
TextRange find( const String& text, TextPosition from = { 0, 0 },
const bool& caseSensitive = true, const bool& wholeWord = false,
const FindReplaceType& type = FindReplaceType::Normal,
TextRange find( const String& text, TextPosition from = { 0, 0 }, bool caseSensitive = true,
bool wholeWord = false, const FindReplaceType& type = FindReplaceType::Normal,
TextRange restrictRange = TextRange() );
TextRange findLast( const String& text, TextPosition from = { 0, 0 },
const bool& caseSensitive = true, const bool& wholeWord = false,
TextRange findLast( const String& text, TextPosition from = { 0, 0 }, bool caseSensitive = true,
bool wholeWord = false,
const FindReplaceType& type = FindReplaceType::Normal,
TextRange restrictRange = TextRange() );
TextRanges findAll( const String& text, const bool& caseSensitive = true,
const bool& wholeWord = false,
TextRanges findAll( const String& text, bool caseSensitive = true, bool wholeWord = false,
const FindReplaceType& type = FindReplaceType::Normal,
TextRange restrictRange = TextRange() );
@@ -642,13 +640,13 @@ class EE_API TextDocument {
LoadStatus loadFromStream( IOStream& file, std::string path, bool callReset );
TextRange findText( String text, TextPosition from = { 0, 0 }, const bool& caseSensitive = true,
const bool& wholeWord = false,
TextRange findText( String text, TextPosition from = { 0, 0 }, bool caseSensitive = true,
bool wholeWord = false,
const FindReplaceType& type = FindReplaceType::Normal,
TextRange restrictRange = TextRange() );
TextRange findTextLast( String text, TextPosition from = { 0, 0 },
const bool& caseSensitive = true, const bool& wholeWord = false,
TextRange findTextLast( String text, TextPosition from = { 0, 0 }, bool caseSensitive = true,
bool wholeWord = false,
const FindReplaceType& type = FindReplaceType::Normal,
TextRange restrictRange = TextRange() );
};

View File

@@ -113,6 +113,8 @@ class EE_API TextRange {
class EE_API TextRanges : public std::vector<TextRange> {
public:
bool isSorted() const { return mIsSorted; }
bool isValid() const {
for ( const auto& selection : *this ) {
if ( !selection.isValid() )
@@ -143,7 +145,12 @@ class EE_API TextRanges : public std::vector<TextRange> {
return false;
}
void sort() { std::sort( begin(), end() ); }
void sort() {
std::sort( begin(), end() );
setSorted();
}
void setSorted() { mIsSorted = true; }
bool merge() {
if ( size() <= 1 )
@@ -176,6 +183,9 @@ class EE_API TextRanges : public std::vector<TextRange> {
ranges.emplace_back( TextRange::fromString( rangeStr ) );
return ranges;
}
protected:
bool mIsSorted{ false };
};
}}} // namespace EE::UI::Doc

View File

@@ -69,6 +69,8 @@ class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecu
int replaceAll( TextSearchParams& search, const String& replace );
virtual Uint32 onKeyDown( const KeyEvent& event );
void refreshHighlight( UICodeEditor* editor );
};
}}} // namespace EE::UI::Tools

View File

@@ -1,3 +1,4 @@
#include <algorithm>
#include <eepp/system/threadpool.hpp>
namespace EE { namespace System {

View File

@@ -2015,8 +2015,8 @@ static std::pair<size_t, size_t> findLastType( const String& str, const String&
}
}
TextRange TextDocument::findText( String text, TextPosition from, const bool& caseSensitive,
const bool& wholeWord, const FindReplaceType& type,
TextRange TextDocument::findText( String text, TextPosition from, bool caseSensitive,
bool wholeWord, const FindReplaceType& type,
TextRange restrictRange ) {
if ( text.empty() )
return TextRange();
@@ -2030,7 +2030,11 @@ TextRange TextDocument::findText( String text, TextPosition from, const bool& ca
return TextRange();
}
if ( !caseSensitive && type != FindReplaceType::LuaPattern )
if ( type == FindReplaceType::LuaPattern && caseSensitive == false )
caseSensitive =
true; // Ignore case insensitive request since this is managed at pattern level
if ( !caseSensitive )
text.toLower();
for ( Int64 i = from.line(); i <= to.line(); i++ ) {
@@ -2064,8 +2068,8 @@ TextRange TextDocument::findText( String text, TextPosition from, const bool& ca
return TextRange();
}
TextRange TextDocument::findTextLast( String text, TextPosition from, const bool& caseSensitive,
const bool& wholeWord, const FindReplaceType& type,
TextRange TextDocument::findTextLast( String text, TextPosition from, bool caseSensitive,
bool wholeWord, const FindReplaceType& type,
TextRange restrictRange ) {
if ( text.empty() )
return TextRange();
@@ -2079,7 +2083,11 @@ TextRange TextDocument::findTextLast( String text, TextPosition from, const bool
return TextRange();
}
if ( !caseSensitive && type != FindReplaceType::LuaPattern )
if ( type == FindReplaceType::LuaPattern && caseSensitive == false )
caseSensitive =
true; // Ignore case insensitive request since this is managed at pattern level
if ( !caseSensitive )
text.toLower();
for ( Int64 i = from.line(); i >= to.line(); i-- ) {
@@ -2115,8 +2123,8 @@ TextRange TextDocument::findTextLast( String text, TextPosition from, const bool
return TextRange();
}
TextRange TextDocument::find( const String& text, TextPosition from, const bool& caseSensitive,
const bool& wholeWord, const FindReplaceType& type,
TextRange TextDocument::find( const String& text, TextPosition from, bool caseSensitive,
bool wholeWord, const FindReplaceType& type,
TextRange restrictRange ) {
std::vector<String> textLines = text.split( '\n', true, true );
@@ -2193,8 +2201,8 @@ TextRange TextDocument::find( const String& text, TextPosition from, const bool&
return TextRange();
}
TextRange TextDocument::findLast( const String& text, TextPosition from, const bool& caseSensitive,
const bool& wholeWord, const FindReplaceType& type,
TextRange TextDocument::findLast( const String& text, TextPosition from, bool caseSensitive,
bool wholeWord, const FindReplaceType& type,
TextRange restrictRange ) {
std::vector<String> textLines = text.split( '\n', true, true );
@@ -2266,9 +2274,8 @@ TextRange TextDocument::findLast( const String& text, TextPosition from, const b
return TextRange();
}
TextRanges TextDocument::findAll( const String& text, const bool& caseSensitive,
const bool& wholeWord, const FindReplaceType& type,
TextRange restrictRange ) {
TextRanges TextDocument::findAll( const String& text, bool caseSensitive, bool wholeWord,
const FindReplaceType& type, TextRange restrictRange ) {
TextRanges all;
TextRange found;
TextPosition from = startOfDoc();
@@ -2283,6 +2290,8 @@ TextRanges TextDocument::findAll( const String& text, const bool& caseSensitive,
all.push_back( found );
}
} while ( found.isValid() );
if ( !all.empty() )
all.setSorted();
return all;
}

View File

@@ -200,22 +200,9 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
mFindInput->setEscapePastedText( true );
UICodeEditor* editor =
getParent()->isType( UI_TYPE_CODEEDITOR ) ? getParent()->asType<UICodeEditor>() : nullptr;
mFindInput->addEventListener( Event::OnTextChanged, [&, editor]( const Event* ) {
mSearchState.text = mFindInput->getText();
if ( editor )
editor->setHighlightWord( mSearchState );
if ( !mSearchState.text.empty() ) {
mDoc->setSelection( { 0, 0 } );
if ( !findNextText( mSearchState ) ) {
mFindInput->addClass( "error" );
} else {
mFindInput->removeClass( "error" );
}
} else {
mFindInput->removeClass( "error" );
mDoc->setSelection( mDoc->getSelection().start() );
}
} );
mFindInput->addEventListener( Event::OnTextChanged,
[&, editor]( const Event* ) { refreshHighlight( editor ); } );
mFindInput->addEventListener( Event::OnTextPasted, [&]( const Event* ) {
if ( mFindInput->getUISceneNode()->getWindow()->getClipboard()->getText().find( '\n' ) !=
String::InvalidPos ) {
@@ -235,14 +222,22 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
setCommand( "find-prev", [this] { findPrevText( mSearchState ); } );
setCommand( "replace-selection",
[this] { mDoc->replaceSelection( mReplaceInput->getText() ); } );
setCommand( "change-case",
[&] { mCaseSensitive->setSelected( !mCaseSensitive->isSelected() ); } );
setCommand( "change-whole-word",
[&] { mWholeWord->setSelected( !mWholeWord->isSelected() ); } );
setCommand( "change-escape-sequence",
[&] { mEscapeSequences->setSelected( !mEscapeSequences->isSelected() ); } );
setCommand( "toggle-lua-pattern",
[&] { mLuaPattern->setSelected( !mLuaPattern->isSelected() ); } );
setCommand( "change-case", [this, editor] {
mCaseSensitive->setSelected( !mCaseSensitive->isSelected() );
refreshHighlight( editor );
} );
setCommand( "change-whole-word", [this, editor] {
mWholeWord->setSelected( !mWholeWord->isSelected() );
refreshHighlight( editor );
} );
setCommand( "change-escape-sequence", [this, editor] {
mEscapeSequences->setSelected( !mEscapeSequences->isSelected() );
refreshHighlight( editor );
} );
setCommand( "toggle-lua-pattern", [this, editor] {
mLuaPattern->setSelected( !mLuaPattern->isSelected() );
refreshHighlight( editor );
} );
mCaseSensitive->setTooltipText( mCaseSensitive->getTooltipText() + " (" +
getKeyBindings().getCommandKeybindString( "change-case" ) +
@@ -316,6 +311,11 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
mPatternBind = UIDataBind<TextDocument::FindReplaceType>::New( &mSearchState.type, mLuaPattern,
luaPatternConverter );
auto valueChangeCb = [this, editor]( const auto& ) { refreshHighlight( editor ); };
mPatternBind->onValueChangeCb = valueChangeCb;
for ( const auto& db : mDataBinds )
db->onValueChangeCb = valueChangeCb;
setVisible( false );
runOnMainThread( [&] { mReady = true; } );
@@ -518,4 +518,21 @@ bool UIDocFindReplace::findAndReplace( TextSearchParams& search, const String& r
}
}
void UIDocFindReplace::refreshHighlight( UICodeEditor* editor ) {
mSearchState.text = mFindInput->getText();
if ( editor )
editor->setHighlightWord( mSearchState );
if ( !mSearchState.text.empty() ) {
mDoc->setSelection( { 0, 0 } );
if ( !findNextText( mSearchState ) ) {
mFindInput->addClass( "error" );
} else {
mFindInput->removeClass( "error" );
}
} else {
mFindInput->removeClass( "error" );
mDoc->setSelection( mDoc->getSelection().start() );
}
};
}}} // namespace EE::UI::Tools

View File

@@ -3338,6 +3338,9 @@ void UICodeEditor::drawMinimap( const Vector2f& start,
!range.inSameLine() )
continue;
if ( ranges.isSorted() && range.end().line() > endidx )
break;
Rectf selRect;
selRect.Top = rect.Top + ( range.start().line() - minimapStartLine ) * lineSpacing;
selRect.Bottom = selRect.Top + charHeight;

View File

@@ -6,6 +6,25 @@ namespace ecode {
DocSearchController::DocSearchController( UICodeEditorSplitter* editorSplitter, App* app ) :
mEditorSplitter( editorSplitter ), mApp( app ) {}
void DocSearchController::refreshHighlight() {
if ( mSearchState.editor && mEditorSplitter->editorExists( mSearchState.editor ) ) {
mSearchState.text = mFindInput->getText();
mSearchState.editor->setHighlightWord( mSearchState.toTextSearchParams() );
if ( !mSearchState.text.empty() ) {
mSearchState.editor->getDocument().setSelection( { 0, 0 } );
if ( !findNextText( mSearchState ) ) {
mFindInput->addClass( "error" );
} else {
mFindInput->removeClass( "error" );
}
} else {
mFindInput->removeClass( "error" );
mSearchState.editor->getDocument().setSelection(
mSearchState.editor->getDocument().getSelection().start() );
}
}
}
void DocSearchController::initSearchBar(
UISearchBar* searchBar, const SearchBarConfig& searchBarConfig,
std::unordered_map<std::string, std::string> keybindings ) {
@@ -62,39 +81,27 @@ void DocSearchController::initSearchBar(
mCaseSensitiveChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.caseSensitive = mCaseSensitiveChk->isChecked();
refreshHighlight();
} );
mEscapeSequenceChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.escapeSequences = mEscapeSequenceChk->isChecked();
refreshHighlight();
} );
mWholeWordChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.wholeWord = mWholeWordChk->isChecked();
refreshHighlight();
} );
mLuaPatternChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.type = mLuaPatternChk->isChecked() ? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
refreshHighlight();
} );
mFindInput->addEventListener( Event::OnTextChanged, [&]( const Event* ) {
if ( mSearchState.editor && mEditorSplitter->editorExists( mSearchState.editor ) ) {
mSearchState.text = mFindInput->getText();
mSearchState.editor->setHighlightWord( mSearchState.toTextSearchParams() );
if ( !mSearchState.text.empty() ) {
mSearchState.editor->getDocument().setSelection( { 0, 0 } );
if ( !findNextText( mSearchState ) ) {
mFindInput->addClass( "error" );
} else {
mFindInput->removeClass( "error" );
}
} else {
mFindInput->removeClass( "error" );
mSearchState.editor->getDocument().setSelection(
mSearchState.editor->getDocument().getSelection().start() );
}
}
} );
mFindInput->addEventListener( Event::OnTextChanged,
[&]( const Event* ) { refreshHighlight(); } );
mFindInput->addEventListener( Event::OnTextPasted, [&]( const Event* ) {
if ( mFindInput->getUISceneNode()->getWindow()->getClipboard()->getText().find( '\n' ) !=
String::InvalidPos ) {

View File

@@ -72,6 +72,7 @@ class DocSearchController {
void selectAll( SearchState& search );
void refreshHighlight();
protected:
UICodeEditorSplitter* mEditorSplitter{ nullptr };
UITextInput* mFindInput{ nullptr };

View File

@@ -86,6 +86,7 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
lsp->getClientManager().getLSPForLang( def.getLSPName(), def.getFiles() );
if ( !found.command.empty() ) {
lang.lsp.name = found.name;
lang.lsp.url = found.url;
lang.lsp.path = Sys::which( String::split( found.command, ' ' )[0] );
lang.lsp.found = !lang.lsp.path.empty();
}
@@ -128,8 +129,12 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
}
for ( const auto& ht : status ) {
table.add_row( { ht.lang, "", ht.lsp.name.empty() ? "None" : ht.lsp.name,
ht.linter.name.empty() ? "None" : ht.linter.name,
std::string lspName = ht.lsp.name.empty() ? "None" : ht.lsp.name;
if ( OutputFormat::Markdown == format && !ht.lsp.name.empty() && !ht.lsp.url.empty() ) {
lspName = "[" + ht.lsp.name + "](" + ht.lsp.url + ")";
}
table.add_row( { ht.lang, "", lspName, ht.linter.name.empty() ? "None" : ht.linter.name,
ht.formatter.name.empty() ? "None" : ht.formatter.name } );
auto& row = table[table.size() - 1];

View File

@@ -25,6 +25,7 @@ class FeaturesHealth {
struct FeatureStatus {
std::string name;
std::string path;
std::string url;
bool found{ false };
};
struct LangHealth {

View File

@@ -802,9 +802,9 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
lsp.language = obj["language"];
lsp.command = parseCommand( obj["command"] );
lsp.name = obj["name"];
lsp.url = obj.value( "url", "" );
}
lsp.url = obj.value( "url", "" );
lsp.commandParameters = obj.value( "command_parameters", lsp.commandParameters );
if ( obj.contains( "initializationOptions" ) )
lsp.initializationOptions = obj["initializationOptions"];