7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-03-30 06:06:55 +00:00

Autocomplete for Execute Command job.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19735
This commit is contained in:
Jeff Young 2025-03-20 16:58:47 +00:00
parent f5cae044d0
commit 9a1e42f228
9 changed files with 140 additions and 66 deletions

View File

@ -20,6 +20,7 @@
#include <build_version.h>
#include <env_vars.h>
#include <settings/environment.h>
#include <core/kicad_algo.h>
#include <map>
@ -27,15 +28,13 @@
#include <wx/translation.h>
#include <wx/utils.h>
using STRING_MAP = std::map<wxString, wxString>;
/**
* List of pre-defined environment variables.
*
* @todo Instead of defining these values here, extract them from elsewhere in the program
* (where they are originally defined).
*/
static const ENV_VAR::ENV_VAR_LIST predefinedEnvVars = {
static const std::vector<wxString> predefinedEnvVars = {
wxS( "KIPRJMOD" ),
ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ),
ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ),
@ -65,12 +64,22 @@ bool ENV_VAR::IsEnvVarImmutable( const wxString& aEnvVar )
}
const ENV_VAR::ENV_VAR_LIST& ENV_VAR::GetPredefinedEnvVars()
const std::vector<wxString>& ENV_VAR::GetPredefinedEnvVars()
{
return predefinedEnvVars;
}
void ENV_VAR::GetEnvVarAutocompleteTokens( wxArrayString* aVars )
{
for( const wxString& var : ENV_VAR::GetPredefinedEnvVars() )
{
if( !alg::contains( *aVars, var ) )
aVars->push_back( var );
}
}
wxString ENV_VAR::GetVersionedEnvVarName( const wxString& aBaseName )
{
int version = 0;
@ -100,43 +109,46 @@ std::optional<wxString> ENV_VAR::GetVersionedEnvVarValue( const ENV_VAR_MAP& aMa
}
static void initialiseEnvVarHelp( STRING_MAP& aMap )
static void initialiseEnvVarHelp( std::map<wxString, wxString>& aMap )
{
// Set up dynamically, as we want to be able to use _() translations,
// which can't be done statically
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) )] =
_( "The base path of locally installed system "
"footprint libraries (.pretty folders).");
_( "The base path of locally installed system footprint libraries (.pretty folders)." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) )] =
_( "The base path of system footprint 3D shapes (.3Dshapes folders).");
_( "The base path of system footprint 3D shapes (.3Dshapes folders)." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) )] =
_( "The base path of the locally installed symbol libraries.");
_( "The base path of the locally installed symbol libraries." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) )] =
_( "A directory containing project templates installed with KiCad.");
_( "A directory containing project templates installed with KiCad." );
aMap[wxS( "KICAD_USER_TEMPLATE_DIR" )] =
_( "Optional. Can be defined if you want to create your own project "
"templates folder.");
_( "Optional. Can be defined if you want to create your own project templates folder." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "3RD_PARTY" ) )] =
_( "A directory containing 3rd party plugins, libraries and other "
"downloadable content.");
_( "A directory containing 3rd party plugins, libraries and other downloadable content." );
aMap[wxS( "KIPRJMOD" )] =
_("Internally defined by KiCad (cannot be edited) and is set "
"to the absolute path of the currently loaded project file. This environment "
"variable can be used to define files and paths relative to the currently loaded "
"project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be defined as a "
"folder containing a project specific footprint library named footprints.pretty." );
_( "Internally defined by KiCad (cannot be edited) and is set to the absolute path of the currently "
"loaded project file. This environment variable can be used to define files and paths relative "
"to the currently loaded project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be "
"defined as a folder containing a project specific footprint library named footprints.pretty." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "SCRIPTING_DIR" ) )] =
_( "A directory containing system-wide scripts installed with KiCad" );
_( "A directory containing system-wide scripts installed with KiCad." );
aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "USER_SCRIPTING_DIR" ) )] =
_( "A directory containing user-specific scripts installed with KiCad" );
_( "A directory containing user-specific scripts installed with KiCad." );
// Deprecated vars
#define DEP( var ) wxString::Format( _( "Deprecated version of %s." ), var )
aMap[wxS( "KICAD_PTEMPLATES" )] =
DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) ) );
aMap[wxS( "KISYS3DMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
aMap[wxS( "KISYSMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) ) );
aMap[wxS( "KICAD_PTEMPLATES" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) ) );
aMap[wxS( "KISYS3DMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
aMap[wxS( "KISYSMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) ) );
aMap[wxS( "KICAD_SYMBOL_DIR" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) );
#undef DEP
@ -145,7 +157,7 @@ static void initialiseEnvVarHelp( STRING_MAP& aMap )
wxString ENV_VAR::LookUpEnvVarHelp( const wxString& aEnvVar )
{
static STRING_MAP envVarHelpText;
static std::map<wxString, wxString> envVarHelpText;
if( envVarHelpText.size() == 0 )
initialiseEnvVarHelp( envVarHelpText );
@ -175,13 +187,10 @@ template<>
std::optional<wxString> ENV_VAR::GetEnvVar( const wxString& aEnvVarName )
{
std::optional<wxString> optValue;
wxString env;
wxString env;
if( wxGetEnv( aEnvVarName, &env ) )
{
optValue = env;
}
return optValue;
}

View File

@ -572,8 +572,8 @@ void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
}
void SCINTILLA_TRICKS::DoTextVarAutocomplete(
const std::function<void( const wxString& xRef, wxArrayString* tokens )>& getTokensFn )
void SCINTILLA_TRICKS::DoTextVarAutocomplete( const std::function<void( const wxString& xRef,
wxArrayString* tokens )>& getTokensFn )
{
wxArrayString autocompleteTokens;
int text_pos = m_te->GetCurrentPos();

View File

@ -28,6 +28,7 @@
#include <kicommon.h>
#include <wx/string.h>
#include <wx/arrstr.h>
#include <map>
#include <vector>
#include <optional>
@ -36,8 +37,6 @@ class ENV_VAR_ITEM;
namespace ENV_VAR
{
using ENV_VAR_LIST = std::vector<wxString>;
/**
* Determine if an environment variable is "predefined", i.e. if the
* name of the variable is special to KiCad, and isn't just a user-specified
@ -51,7 +50,12 @@ namespace ENV_VAR
/**
* Get the list of pre-defined environment variables.
*/
KICOMMON_API const ENV_VAR_LIST& GetPredefinedEnvVars();
KICOMMON_API const std::vector<wxString>& GetPredefinedEnvVars();
/**
* Return autocomplete tokens for environment variables for Scintilla.
*/
KICOMMON_API void GetEnvVarAutocompleteTokens( wxArrayString* aVars );
/**
* Construct a versioned environment variable based on this KiCad major version.

View File

@ -20,18 +20,46 @@
#include <dialogs/dialog_executecommand_job_settings.h>
#include <jobs/job_special_execute.h>
#include <scintilla_tricks.h>
#include <env_vars.h>
DIALOG_EXECUTECOMMAND_JOB_SETTINGS::DIALOG_EXECUTECOMMAND_JOB_SETTINGS( wxWindow* aParent,
JOB_SPECIAL_EXECUTE* aJob ) :
DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE( aParent ),
m_job( aJob )
m_job( aJob ),
m_scintillaTricks( nullptr )
{
m_scintillaTricks = new SCINTILLA_TRICKS( m_textCtrlCommand, wxT( "{}" ), false,
// onAcceptFn
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},
// onCharFn
[this]( wxStyledTextEvent& aEvent )
{
m_scintillaTricks->DoTextVarAutocomplete(
// getTokensFn
[]( const wxString& xRef, wxArrayString* tokens )
{
ENV_VAR::GetEnvVarAutocompleteTokens( tokens );
} );
} );
SetupStandardButtons();
finishDialogSettings();
}
DIALOG_EXECUTECOMMAND_JOB_SETTINGS::~DIALOG_EXECUTECOMMAND_JOB_SETTINGS()
{
delete m_scintillaTricks;
}
bool DIALOG_EXECUTECOMMAND_JOB_SETTINGS::TransferDataFromWindow()
{
m_job->m_command = m_textCtrlCommand->GetValue();

View File

@ -21,17 +21,23 @@
#include <dialogs/dialog_executecommand_job_settings_base.h>
class JOB_SPECIAL_EXECUTE;
class SCINTILLA_TRICKS;
class DIALOG_EXECUTECOMMAND_JOB_SETTINGS: public DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE
{
public:
DIALOG_EXECUTECOMMAND_JOB_SETTINGS( wxWindow* aParent, JOB_SPECIAL_EXECUTE* aJob );
~DIALOG_EXECUTECOMMAND_JOB_SETTINGS();
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
private:
void OnRecordOutputClicked( wxCommandEvent& event ) override;
private:
JOB_SPECIAL_EXECUTE* m_job;
void OnRecordOutputClicked( wxCommandEvent& event ) override;
SCINTILLA_TRICKS* m_scintillaTricks;
};

View File

@ -25,13 +25,39 @@ DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE::DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE
m_textCommand = new wxStaticText( this, wxID_ANY, _("Command:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textCommand->Wrap( -1 );
fgSizer1->Add( m_textCommand, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
fgSizer1->Add( m_textCommand, 0, wxALL, 5 );
m_textCtrlCommand = new wxTextCtrl( this, wxID_ANY, _("Enter the command line to run SPICE\nUsually '<path to SPICE binary> \"%I\"'\n%I will be replaced by the netlist filepath"), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
m_textCtrlCommand->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
m_textCtrlCommand->SetMinSize( wxSize( 400,-1 ) );
fgSizer1->Add( m_textCtrlCommand, 1, wxEXPAND|wxRIGHT, 5 );
m_textCtrlCommand = new wxStyledTextCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString );
m_textCtrlCommand->SetUseTabs( false );
m_textCtrlCommand->SetTabWidth( 4 );
m_textCtrlCommand->SetIndent( 4 );
m_textCtrlCommand->SetTabIndents( false );
m_textCtrlCommand->SetBackSpaceUnIndents( false );
m_textCtrlCommand->SetViewEOL( false );
m_textCtrlCommand->SetViewWhiteSpace( false );
m_textCtrlCommand->SetMarginWidth( 2, 0 );
m_textCtrlCommand->SetIndentationGuides( false );
m_textCtrlCommand->SetReadOnly( false );
m_textCtrlCommand->SetMarginWidth( 1, 0 );
m_textCtrlCommand->SetMarginWidth( 0, 0 );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS );
m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("BLACK") ) );
m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("WHITE") ) );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS );
m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("BLACK") ) );
m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("WHITE") ) );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS );
m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("BLACK") ) );
m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("WHITE") ) );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS );
m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("BLACK") ) );
m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("WHITE") ) );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY );
m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY );
m_textCtrlCommand->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
m_textCtrlCommand->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
fgSizer1->Add( m_textCtrlCommand, 1, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 5 );
m_textOutputPath = new wxStaticText( this, wxID_ANY, _("Output path:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textOutputPath->Wrap( -1 );

View File

@ -82,7 +82,7 @@
<property name="vgap">5</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
@ -142,11 +142,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxRIGHT</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="false">
<object class="wxStyledTextCtrl" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -155,6 +155,7 @@
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="backspace_unindents">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
@ -171,17 +172,19 @@
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font">,90,400,-1,70,0</property>
<property name="folding">0</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="indentation_guides">0</property>
<property name="line_numbers">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">400,-1</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_textCtrlCommand</property>
<property name="pane_border">1</property>
@ -190,18 +193,18 @@
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="read_only">0</property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxTE_MULTILINE</property>
<property name="subclass">; ; forward_declare</property>
<property name="tab_indents">0</property>
<property name="tab_width">4</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">Enter the command line to run SPICE&#x0A;Usually &apos;&lt;path to SPICE binary&gt; &quot;%I&quot;&apos;&#x0A;%I will be replaced by the netlist filepath</property>
<property name="use_tabs">0</property>
<property name="view_eol">0</property>
<property name="view_whitespace">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>

View File

@ -17,6 +17,7 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/stc/stc.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/checkbox.h>
@ -34,7 +35,7 @@ class DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE : public DIALOG_SHIM
protected:
wxStaticText* m_textCommand;
wxTextCtrl* m_textCtrlCommand;
wxStyledTextCtrl* m_textCtrlCommand;
wxStaticText* m_textOutputPath;
wxTextCtrl* m_textCtrlOutputPath;
wxCheckBox* m_cbRecordOutput;

View File

@ -389,12 +389,9 @@ void JOBS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
menu.Append( JOB_DESCRIPTION, _( "Edit Job Description" ) );
menu.Append( JOB_PROPERTIES, _( "Edit Job Settings..." ) );
menu.AppendSeparator();
menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C",
_( "Copy selected cells to clipboard" ) );
menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel",
_( "Delete selected jobs" ) );
menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A",
_( "Select all jobs" ) );
menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C", _( "Copy selected cells to clipboard" ) );
menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel", _( "Delete selected jobs" ) );
menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A", _( "Select all jobs" ) );
menu.Enable( JOB_DESCRIPTION, selectedRows.size() == 1 );
menu.Enable( JOB_PROPERTIES, selectedRows.size() == 1 );
@ -632,13 +629,13 @@ bool PANEL_JOBSET::OpenJobOptionsForListItem( size_t aItemIndex )
DIALOG_EXECUTECOMMAND_JOB_SETTINGS dialog( m_frame, specialJob );
if( dialog.ShowModal() == wxID_OK )
// QuasiModal for Scintilla autocomplete
if( dialog.ShowQuasiModal() == wxID_OK )
success = true;
}
else if( job.m_job->GetType() == "special_copyfiles" )
{
JOB_SPECIAL_COPYFILES* specialJob =
static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() );
JOB_SPECIAL_COPYFILES* specialJob = static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() );
DIALOG_COPYFILES_JOB_SETTINGS dialog( m_frame, specialJob );
if( dialog.ShowModal() == wxID_OK )