ecode: Fix in tooltip. Added static Text::wrapText. Fix export of syntax definitions.

eepp: Started working on a Git plugin.
This commit is contained in:
Martín Lucas Golini
2023-12-16 22:24:35 -03:00
parent b41cbfe1ce
commit e09b62a40d
16 changed files with 714 additions and 140 deletions

View File

@@ -0,0 +1,250 @@
#include "gitplugin.hpp"
#include <eepp/graphics/primitives.hpp>
#include <eepp/system/filesystem.hpp>
#include <eepp/system/scopedop.hpp>
#include <eepp/ui/doc/syntaxdefinitionmanager.hpp>
#include <eepp/ui/uipopupmenu.hpp>
#include <eepp/ui/uitooltip.hpp>
#include <nlohmann/json.hpp>
using namespace EE::UI::Doc;
using json = nlohmann::json;
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
#define GIT_THREADED 1
#else
#define GIT_THREADED 0
#endif
namespace ecode {
UICodeEditorPlugin* GitPlugin::New( PluginManager* pluginManager ) {
return eeNew( GitPlugin, ( pluginManager, false ) );
}
UICodeEditorPlugin* GitPlugin::NewSync( PluginManager* pluginManager ) {
return eeNew( GitPlugin, ( pluginManager, true ) );
}
GitPlugin::GitPlugin( PluginManager* pluginManager, bool sync ) : PluginBase( pluginManager ) {
if ( sync ) {
load( pluginManager );
} else {
#if defined( GIT_THREADED ) && GIT_THREADED == 1
mThreadPool->run( [&, pluginManager] { load( pluginManager ); } );
#else
load( pluginManager );
#endif
}
}
GitPlugin::~GitPlugin() {
mShuttingDown = true;
}
void GitPlugin::load( PluginManager* pluginManager ) {
AtomicBoolScopedOp loading( mLoading, true );
pluginManager->subscribeMessages( this,
[this]( const auto& notification ) -> PluginRequestHandle {
return processMessage( notification );
} );
std::string path = pluginManager->getPluginsPath() + "git.json";
if ( FileSystem::fileExists( path ) ||
FileSystem::fileWrite( path, "{\n \"config\":{},\n \"keybindings\":{}\n}\n" ) ) {
mConfigPath = path;
}
std::string data;
if ( !FileSystem::fileGet( path, data ) )
return;
mConfigHash = String::hash( data );
json j;
try {
j = json::parse( data, nullptr, true, true );
} catch ( const json::exception& e ) {
Log::error( "GitPlugin::load - Error parsing config from path %s, error: %s, config "
"file content:\n%s",
path.c_str(), e.what(), data.c_str() );
// Recreate it
j = json::parse( "{\n \"config\":{},\n \"keybindings\":{},\n}\n", nullptr, true, true );
}
bool updateConfigFile = false;
if ( j.contains( "config" ) ) {
auto& config = j["config"];
if ( config.contains( "statusbar_display_branch" ) )
mStatusBarDisplayBranch = config.value( "statusbar_display_branch", true );
else {
config["statusbar_display_branch"] = mStatusBarDisplayBranch;
updateConfigFile = true;
}
if ( config.contains( "statusbar_display_modifications" ) )
mStatusBarDisplayModifications =
config.value( "statusbar_display_modifications", true );
else {
config["statusbar_display_modifications"] = mStatusBarDisplayModifications;
updateConfigFile = true;
}
}
if ( updateConfigFile ) {
std::string newData = j.dump( 2 );
if ( newData != data ) {
FileSystem::fileWrite( path, newData );
mConfigHash = String::hash( newData );
}
}
mGit = std::make_unique<Git>( "", pluginManager->getWorkspaceFolder() );
mGitFound = !mGit->getGitPath().empty();
subscribeFileSystemListener();
mReady = true;
fireReadyCbs();
setReady();
}
PluginRequestHandle GitPlugin::processMessage( const PluginMessage& msg ) {
switch ( msg.type ) {
case PluginMessageType::WorkspaceFolderChanged: {
mGit->setProjectPath( msg.asJSON()["folder"] );
break;
}
default:
break;
}
return PluginRequestHandle::empty();
}
void GitPlugin::onFileSystemEvent( const FileEvent& ev, const FileInfo& file ) {
PluginBase::onFileSystemEvent( ev, file );
if ( mShuttingDown || isLoading() )
return;
}
void GitPlugin::displayTooltip( UICodeEditor* editor, const Git::BlameData& blame,
const Vector2f& position ) {
// HACK: Gets the old font style to restore it when the tooltip is hidden
UITooltip* tooltip = editor->createTooltip();
if ( tooltip == nullptr )
return;
String str(
blame.error.empty()
? String::format( "%s: %s\n%s: %s (%s)\n%s: %s\n\n%s",
i18n( "commit", "Commit" ).toUtf8().c_str(), blame.commitHash.c_str(),
i18n( "author", "Author" ).toUtf8().c_str(), blame.author.c_str(),
blame.authorEmail.c_str(), i18n( "date", "Date" ).toUtf8().c_str(),
blame.date.c_str(), blame.commitMessage.c_str() )
: blame.error );
Text::wrapText( str, PixelDensity::dpToPx( 400 ), tooltip->getFontStyleConfig(),
editor->getTabWidth() );
editor->setTooltipText( str );
mTooltipInfoShowing = true;
mOldTextStyle = tooltip->getFontStyle();
mOldTextAlign = tooltip->getHorizontalAlign();
mOldDontAutoHideOnMouseMove = tooltip->dontAutoHideOnMouseMove();
mOldUsingCustomStyling = tooltip->getUsingCustomStyling();
tooltip->setHorizontalAlign( UI_HALIGN_LEFT );
tooltip->setPixelsPosition( tooltip->getTooltipPosition( position ) );
tooltip->setDontAutoHideOnMouseMove( false );
tooltip->setUsingCustomStyling( true );
// const auto& syntaxDef = SyntaxDefinitionManager::instance()->getByLSPName( "markdown" );
// SyntaxTokenizer::tokenizeText( syntaxDef, editor->getColorScheme(), *tooltip->getTextCache(), 0,
// 0xFFFFFFFF, true, "\n\t " );
// tooltip->notifyTextChangedFromTextCache();
if ( editor->hasFocus() && !tooltip->isVisible() )
tooltip->show();
}
void GitPlugin::hideTooltip( UICodeEditor* editor ) {
mTooltipInfoShowing = false;
UITooltip* tooltip = nullptr;
if ( editor && ( tooltip = editor->getTooltip() ) && tooltip->isVisible() ) {
editor->setTooltipText( "" );
tooltip->hide();
// Restore old tooltip state
tooltip->setFontStyle( mOldTextStyle );
tooltip->setHorizontalAlign( mOldTextAlign );
tooltip->setUsingCustomStyling( mOldUsingCustomStyling );
tooltip->setDontAutoHideOnMouseMove( mOldDontAutoHideOnMouseMove );
}
}
void GitPlugin::onRegisterListeners( UICodeEditor* editor, std::vector<Uint32>& listeners ) {
listeners.push_back(
editor->addEventListener( Event::OnCursorPosChange, [this, editor]( const Event* ) {
if ( mTooltipInfoShowing )
hideTooltip( editor );
} ) );
}
void GitPlugin::blame( UICodeEditor* editor ) {
if ( !mGitFound ) {
editor->setTooltipText(
i18n( "git_not_found",
"Git binary not found.\nPlease check that git is accesible via PATH" ) );
return;
}
mThreadPool->run( [this, editor]() {
auto blame = mGit->blame( editor->getDocument().getFilePath(),
editor->getDocument().getSelection().start().line() );
editor->runOnMainThread( [this, editor, blame] {
displayTooltip(
editor, blame,
editor->getScreenPosition( editor->getDocument().getSelection().start() )
.getPosition() );
} );
} );
}
void GitPlugin::onRegister( UICodeEditor* editor ) {
PluginBase::onRegister( editor );
if ( !editor->hasDocument() )
return;
auto& doc = editor->getDocument();
doc.setCommand( "git-blame", [this]( TextDocument::Client* client ) {
blame( static_cast<UICodeEditor*>( client ) );
} );
}
void GitPlugin::onUnregister( UICodeEditor* editor ) {
PluginBase::onUnregister( editor );
}
bool GitPlugin::onCreateContextMenu( UICodeEditor*, UIPopUpMenu* menu, const Vector2i& /*position*/,
const Uint32& /*flags*/ ) {
if ( !mGitFound )
return false;
menu->addSeparator();
auto addFn = [this, menu]( const std::string& txtKey, const std::string& txtVal,
const std::string& icon = "" ) {
menu->add( i18n( txtKey, txtVal ),
!icon.empty() ? mManager->getUISceneNode()->findIcon( icon )->getSize(
PixelDensity::dpToPxI( 12 ) )
: nullptr,
KeyBindings::keybindFormat( mKeyBindings[txtKey] ) )
->setId( txtKey );
};
addFn( "git-blame", "Git Blame" );
return false;
}
} // namespace ecode