Improvements when opening binary files from drag and drop and from the tree-view (SpartanJ/ecode#589).

Fixes a bug that prevented signature help to not be displayed.
This commit is contained in:
Martín Lucas Golini
2025-07-13 19:22:31 -03:00
parent 8a8384ca59
commit 2df4e88836
8 changed files with 152 additions and 26 deletions
+4 -2
View File
@@ -37,9 +37,11 @@ struct DocumentContentChange {
class EE_API TextDocument {
public:
static bool isTextDocummentCommand( std::string_view cmd );
static bool isTextDocummentCommand( std::string_view cmd );
static bool isTextDocummentCommand( String::HashType cmdHash );
static bool isTextDocummentCommand( String::HashType cmdHash );
static bool fileMightBeBinary( const std::string& file );
enum class UndoRedo { Undo, Redo };
+28
View File
@@ -28,6 +28,34 @@ static constexpr char DEFAULT_NON_WORD_CHARS[] = " \t\n/\\()\"':,.;<>~!@#$%^&*|+
static UnorderedSet<String::HashType> TEXT_DOCUMENT_COMMANDS = {};
bool TextDocument::fileMightBeBinary( const std::string& file ) {
static constexpr std::array<char, 4> BINARY_STR = { 0, 0, 0, 0 };
static constexpr size_t MAX_READ = 4096;
IOStreamFile f( file );
if ( !f.isOpen() ) {
// Handle file opening failure (e.g., return false or throw)
return false;
}
std::array<char, MAX_READ> buffer;
size_t bytesToRead = std::min<size_t>( MAX_READ, f.getSize() );
if ( bytesToRead < BINARY_STR.size() ) {
// File is too small to contain the binary sequence
return false;
}
size_t bytesRead = f.read( buffer.data(), bytesToRead );
if ( bytesRead < BINARY_STR.size() ) {
// Not enough bytes read to contain the binary sequence
return false;
}
auto res = std::search( buffer.begin(), buffer.begin() + bytesRead, BINARY_STR.begin(),
BINARY_STR.end() );
return res != buffer.begin() + bytesRead;
}
bool TextDocument::isTextDocummentCommand( std::string_view cmd ) {
return TEXT_DOCUMENT_COMMANDS.contains( String::hash( cmd ) );
}
+77 -21
View File
@@ -2230,21 +2230,32 @@ void App::loadImageFromPath( const std::string& path ) {
loadImageFromMedium( path, false );
}
static bool isVideoExtension( std::string_view ext ) {
static constexpr std::array<std::string_view, 10> videoExtensions = {
"mp4", "mov", "mkv", "avi", "wmv", "webm", "flv", "mpg", "mpeg", "m4v" };
for ( const auto& videoExt : videoExtensions )
if ( String::iequals( ext, videoExt ) )
return true;
return false;
}
static bool isDocumentExtension( std::string_view ext ) {
static constexpr std::array<std::string_view, 3> videoExtensions = { "doc", "docx", "pdf" };
for ( const auto& videoExt : videoExtensions )
if ( String::iequals( ext, videoExt ) )
return true;
return false;
void App::openFileFromPath( const std::string& path ) {
std::string ext = FileSystem::fileExtension( path );
bool canOpenBinaryFile = PathHelper::isOpenExternalExtension( ext );
if ( !canOpenBinaryFile && TextDocument::fileMightBeBinary( path ) ) {
auto msgBox = UIMessageBox::New(
UIMessageBox::YES_NO,
i18n( "open_binary_file_warning",
"File looks like a binary file. Are you sure "
"you want to open it as a document?\nOtherwise it will try to open the "
"file with an external application." ) );
msgBox->getButtonOK()->setText( i18n( "open_as_document", "Open as document" ) );
msgBox->getButtonOK()->getIcon()->setVisible( false );
msgBox->getButtonCancel()->setText( i18n( "open_externally", "Open externally" ) );
msgBox->getButtonCancel()->getIcon()->setVisible( false );
msgBox->on( Event::OnConfirm, [this, path]( auto ) { loadFileFromPath( path ); } );
msgBox->on( Event::OnCancel, [path]( auto ) {
FileInfo f( path );
if ( f.isExecutable() )
Sys::execute( path );
else
Engine::instance()->openURI( path );
} );
msgBox->showWhenReady();
} else {
loadFileFromPath( path );
}
}
bool App::loadFileFromPath(
@@ -2263,7 +2274,7 @@ bool App::loadFileFromPath(
return false;
}
if ( isVideoExtension( ext ) || isDocumentExtension( ext ) ) {
if ( PathHelper::isOpenExternalExtension( ext ) ) {
Engine::instance()->openURI( path );
} else if ( Image::isImageExtension( path ) && Image::isImage( path ) && ext != "svg" ) {
loadImageFromPath( path );
@@ -3010,7 +3021,7 @@ void App::initProjectTreeViewUI() {
if ( !tab ) {
FileInfo fileInfo( path );
if ( fileInfo.exists() && fileInfo.isRegularFile() )
loadFileFromPath( path );
openFileFromPath( path );
} else {
tab->getTabWidget()->setTabSelected( tab );
}
@@ -3797,10 +3808,55 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
if ( onlyDirectories ) {
loadFolder( mPathsToLoad[lastDirIdx] );
} else {
// Load only files even if there are directories
for ( const auto& file : mPathsToLoad ) {
if ( !FileSystem::isDirectory( file ) )
onFileDropped( file );
int mightBeBinaryCount = 0;
for ( const auto& file : mPathsToLoad )
if ( !FileSystem::isDirectory( file ) &&
TextDocument::fileMightBeBinary( file ) )
mightBeBinaryCount++;
if ( mightBeBinaryCount ) {
if ( mightBeBinaryCount == 1 && mPathsToLoad.size() == 1 ) {
FileInfo f( mPathsToLoad[0] );
if ( f.isExecutable() )
Sys::execute( mPathsToLoad[0] );
else
Engine::instance()->openURI( mPathsToLoad[0] );
} else {
UIMessageBox* msgBox = UIMessageBox::New(
UIMessageBox::OK_CANCEL,
i18n( "dropped_binary_files_open_warn",
"Some of the files seem to be binary.\nDo you want to "
"open them as document? Otherwise they will be ignored "
"for loading." ) );
msgBox->getButtonOK()->setText( i18n( "open", "Open" ) );
msgBox->getButtonOK()->getIcon()->setVisible( false );
msgBox->getButtonCancel()->setText( i18n( "ignore", "Ignore" ) );
msgBox->getButtonCancel()->getIcon()->setVisible( false );
msgBox->on( Event::OnConfirm,
[this, pathsToLoad = mPathsToLoad]( const Event* ) {
for ( const auto& file : pathsToLoad ) {
if ( !FileSystem::isDirectory( file ) )
onFileDropped( file );
}
} );
msgBox->on( Event::OnCancel,
[this, pathsToLoad = mPathsToLoad]( const Event* ) {
for ( const auto& file : pathsToLoad ) {
if ( !FileSystem::isDirectory( file ) &&
!TextDocument::fileMightBeBinary( file ) )
onFileDropped( file );
}
} );
msgBox->setTitle( i18n( "warning", "Warning" ) );
msgBox->center();
msgBox->showWhenReady();
}
} else {
// Load only files even if there are directories
for ( const auto& file : mPathsToLoad ) {
if ( !FileSystem::isDirectory( file ) )
onFileDropped( file );
}
}
}
+2
View File
@@ -88,6 +88,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
std::shared_ptr<ThreadPool> getThreadPool() const;
void openFileFromPath( const std::string& path );
bool loadFileFromPath( std::string path, bool inNewTab = true,
UICodeEditor* codeEditor = nullptr,
std::function<void( UICodeEditor*, const std::string& )> onLoaded =
+27
View File
@@ -0,0 +1,27 @@
#include "pathhelper.hpp"
namespace ecode {
bool PathHelper::isVideoExtension( std::string_view ext ) {
static constexpr std::array<std::string_view, 10> extensions = {
"mp4", "mov", "mkv", "avi", "wmv", "webm", "flv", "mpg", "mpeg", "m4v" };
for ( const auto& cext : extensions )
if ( String::iequals( ext, cext ) )
return true;
return false;
}
bool PathHelper::isDocumentExtension( std::string_view ext ) {
static constexpr std::array<std::string_view, 5> extensions = { "doc", "docx", "pdf", "xls",
"xlsx" };
for ( const auto& cext : extensions )
if ( String::iequals( ext, cext ) )
return true;
return false;
}
bool PathHelper::isOpenExternalExtension( std::string_view ext ) {
return isVideoExtension( ext ) || isDocumentExtension( ext );
}
} // namespace ecode
+8
View File
@@ -51,6 +51,14 @@ template <typename T> static std::pair<T, TextPosition> getPathAndPosition( cons
return { path, { 0, 0 } };
}
struct PathHelper {
static bool isVideoExtension( std::string_view ext );
static bool isDocumentExtension( std::string_view ext );
static bool isOpenExternalExtension( std::string_view ext );
};
} // namespace ecode
#endif // ECODE_PATHHELPER_HPP
@@ -904,6 +904,8 @@ AutoCompletePlugin::processSignatureHelp( const LSPSignatureHelp& signatureHelp
editor->runOnMainThread( [this, editor, signatures = std::move( signatures )] {
mSignatureHelpVisible = true;
mSignatureHelp = signatures;
if ( mSignatureHelpSelected >= static_cast<Int32>( mSignatureHelp.signatures.size() ) )
mSignatureHelpSelected = 0;
if ( mSignatureHelp.signatures.empty() )
resetSignatureHelp();
editor->invalidateDraw();
+4 -3
View File
@@ -1,4 +1,5 @@
#include "settingsmenu.hpp"
#include <filesystem>
namespace fs = std::filesystem;
@@ -2354,7 +2355,7 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) {
} else if ( "new_folder" == id ) {
mApp->newFolder( file );
} else if ( "open_file" == id ) {
mApp->loadFileFromPath( file.getFilepath() );
mApp->openFileFromPath( file.getFilepath() );
} else if ( "remove" == id ) {
deleteFileDialog( file );
} else if ( "duplicate_file" == id ) {
@@ -2552,8 +2553,8 @@ UIMenu* SettingsMenu::createFontHintMenu() {
const auto fontHintMenuRefresh = [this] {
const auto& cfg = mApp->getConfig();
auto el =
mFontHintMenu->find( "hint_" + FontTrueType::fontHintingToString( cfg.ui.fontHinting ) );
auto el = mFontHintMenu->find( "hint_" +
FontTrueType::fontHintingToString( cfg.ui.fontHinting ) );
if ( el && el->isType( UI_TYPE_MENURADIOBUTTON ) )
el->asType<UIMenuRadioButton>()->setActive( true );
};