Skip to content

Commit 12137b8

Browse files
committed
Update Terminal Input Handling And Process Execution
Improve the built-in terminal experience by routing key events through the active terminal control when it has focus, so input handling works more reliably for embedded terminals. The default Windows terminal choice is also updated to PowerShell, reflecting the preferred shell on that platform. This change additionally modernizes Windows process execution in the safe command runner by delegating process launch and output collection to the assistant process helper, while preserving shutdown-aware output handling. At the application level, startup now detaches from the console when possible, and the global event filter is extended so registered callbacks can consume events instead of only observing them. * Terminal * Process Execution * Event Filtering **Generated by CodeLite** Signed-off-by: Eran Ifrah <eran@codelite.org>
1 parent 47b0549 commit 12137b8

File tree

8 files changed

+63
-77
lines changed

8 files changed

+63
-77
lines changed

CodeLite/AsyncProcess/winprocess_impl.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,6 @@ thread_local ClosePseudoConsole_T ClosePseudoConsoleFunc = nullptr;
7171

7272
using HPCON = HANDLE;
7373

74-
/**
75-
* @class ConsoleAttacher
76-
* @date 11/03/10
77-
* @brief a helper class to attach this process to a process' console
78-
* this allows us to write directly into that process console-input-buffer
79-
* One should check isAttached once this object is constructed
80-
*/
81-
class ConsoleAttacher
82-
{
83-
public:
84-
bool isAttached;
85-
86-
public:
87-
ConsoleAttacher(long pid) { isAttached = AttachConsole(pid); }
88-
89-
~ConsoleAttacher()
90-
{
91-
if (isAttached) {
92-
FreeConsole();
93-
}
94-
isAttached = false;
95-
}
96-
};
97-
9874
static bool CheckIsAlive(HANDLE hProcess)
9975
{
10076
DWORD dwExitCode;
@@ -418,7 +394,6 @@ IProcess* WinProcessImpl::Execute(
418394
LOG_IF_TRACE { clDEBUG1() << "Running process:" << cmd << endl; }
419395
BOOL ret = FALSE;
420396
{
421-
ConsoleAttacher ca(prc->GetPid());
422397
ret = CreateProcess(NULL,
423398
cmd.wchar_str(), // shell line execution command
424399
NULL, // process security attributes

CodeLite/event_notifier.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,10 @@ int EventNotifier::FilterEvent(wxEvent& event)
139139
return wxEventFilter::Event_Skip;
140140
}
141141

142+
for (auto& cb : iter->second) {
143+
if (cb.callback(event)) {
144+
return wxEventFilter::Event_Processed;
145+
}
146+
}
142147
return wxEventFilter::Event_Skip;
143148
}

CodeLite/procutils.cpp

Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "AsyncProcess/asyncprocess.h"
2828
#include "StringUtils.h"
29+
#include "assistant/Process.hpp"
2930
#include "cl_command_event.h"
3031
#include "file_logger.h"
3132
#include "fileutils.h"
@@ -500,56 +501,29 @@ int ProcUtils::SafeExecuteCommand(const wxString& command,
500501
std::shared_ptr<std::atomic_bool> shutdown_flag)
501502
{
502503
#ifdef __WXMSW__
503-
wxString errMsg;
504-
LOG_IF_TRACE { clDEBUG1() << "executing process:" << command << endl; }
505-
std::unique_ptr<WinProcess> proc{WinProcess::Execute(command, errMsg)};
506-
if (!proc) {
507-
return wxNOT_FOUND;
508-
}
509-
510-
// wait for the process to terminate
511-
wxString tmpbuf;
512-
wxString buff;
513-
514-
LOG_IF_TRACE { clDEBUG1() << "reading process output..." << endl; }
515-
bool shutdown_cleanly{true};
516-
while (proc->IsAlive()) {
517-
if (shutdown_flag && shutdown_flag->load()) {
518-
// Check for termination flag state
519-
shutdown_cleanly = false;
520-
break;
504+
auto argv = StringUtils::BuildArgv(command);
505+
auto argv_std = StringUtils::ToStdStrings(argv);
506+
std::string accumlated_output;
507+
auto output_cb = [shutdown_flag, &accumlated_output](const std::string& out, const std::string& err) -> bool {
508+
if (!out.empty()) {
509+
accumlated_output += out;
521510
}
522-
523-
tmpbuf.Clear();
524-
if (proc->Read(tmpbuf)) {
525-
// as long as we read something, don't sleep...
526-
buff << tmpbuf;
527-
} else {
528-
wxThread::Sleep(1);
511+
if (!err.empty()) {
512+
accumlated_output += err;
529513
}
530-
}
514+
return !shutdown_flag->load();
515+
};
531516

532-
int exit_code{-1};
533-
if (shutdown_cleanly) {
534-
tmpbuf.Clear();
535-
exit_code = proc->GetExitCode();
536-
LOG_IF_TRACE
537-
{
538-
clDEBUG1() << "process terminated with exit code:" << exit_code << endl;
539-
// Read any unread output
540-
clDEBUG1() << "reading process output remainder..." << endl;
541-
}
542-
proc->Read(tmpbuf);
543-
while (!tmpbuf.IsEmpty()) {
544-
buff << tmpbuf;
545-
tmpbuf.Clear();
546-
proc->Read(tmpbuf);
547-
}
548-
proc->Cleanup();
549-
LOG_IF_TRACE { clDEBUG1() << "reading process output remainder...done" << endl; }
517+
int exit_code = assistant::Process::RunProcessAndWait(argv_std, output_cb);
518+
wxString out_str = wxString::FromUTF8(accumlated_output);
519+
LOG_IF_TRACE
520+
{
521+
clDEBUG1() << "process terminated with exit code:" << exit_code << endl;
522+
// Read any unread output
523+
clDEBUG1() << "reading process output remainder..." << endl;
550524
}
551525
// Convert buff into wxArrayString
552-
output = ::wxStringTokenize(buff, "\n", wxTOKEN_STRTOK);
526+
output = ::wxStringTokenize(out_str, "\n", wxTOKEN_STRTOK);
553527
return exit_code;
554528
#else
555529
return Popen(command, output, shutdown_flag);

LiteEditor/app.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,9 @@ bool CodeLiteApp::OnInit()
517517
// CodeLite itself :/
518518
FileLogger::OpenLog("codelite.log", clConfig::Get().Read(kConfigLogVerbosity, FileLogger::Error));
519519
clDEBUG() << "Starting codelite..." << endl;
520+
if (FreeConsole()) {
521+
clSYSTEM() << "Successfully detached from console" << endl;
522+
}
520523

521524
// Copy gdb pretty printers from the installation folder to a writeable location
522525
// this is needed because python complies the files and in most cases the user
@@ -1185,6 +1188,4 @@ void CodeLiteApp::FinalizeShutdown()
11851188
clDEBUG() << "Finalizing shutdown...success" << endl;
11861189
}
11871190

1188-
int CodeLiteApp::FilterEvent(wxEvent& event) {
1189-
return EventNotifier::Get()->FilterEvent(event);
1190-
}
1191+
int CodeLiteApp::FilterEvent(wxEvent& event) { return EventNotifier::Get()->FilterEvent(event); }

Plugin/wxTerminalCtrl/clBuiltinTerminalPane.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ std::map<wxString, wxString> LocateDefaultTerminals()
2828
{
2929
std::map<wxString, wxString> terminals;
3030
auto bash = ThePlatform->Which("bash");
31-
auto cmd = ThePlatform->Which("cmd");
31+
auto cmd = ThePlatform->Which("powershell");
3232
if (bash.has_value()) {
3333
terminals.insert(
3434
{wxString::Format("%s --login -i", bash.value()), wxString::Format("%s --login -i", bash.value())});
@@ -77,10 +77,39 @@ clBuiltinTerminalPane::clBuiltinTerminalPane(wxWindow* parent, wxWindowID id)
7777
GetSizer()->Fit(this);
7878
m_book->Bind(wxEVT_BOOK_PAGE_CHANGED, &clBuiltinTerminalPane::OnPageChanged, this);
7979
EventNotifier::Get()->Bind(wxEVT_WORKSPACE_LOADED, &clBuiltinTerminalPane::OnWorkspaceLoaded, this);
80+
81+
auto on_key_down = [this](wxEvent& event) -> bool {
82+
auto terminal = GetActiveTerminal();
83+
CHECK_PTR_RET_FALSE(terminal);
84+
CHECK_COND_RET_FALSE(terminal->HasFocus());
85+
wxKeyEvent* key_event = dynamic_cast<wxKeyEvent*>(&event);
86+
if (!key_event) {
87+
return false;
88+
}
89+
return terminal->GetEventHandler()->ProcessEvent(*key_event);
90+
};
91+
auto on_char_hook = [this](wxEvent& event) -> bool {
92+
auto terminal = GetActiveTerminal();
93+
CHECK_PTR_RET_FALSE(terminal);
94+
CHECK_COND_RET_FALSE(terminal->HasFocus());
95+
wxKeyEvent* key_event = dynamic_cast<wxKeyEvent*>(&event);
96+
if (!key_event) {
97+
return false;
98+
}
99+
return terminal->GetEventHandler()->ProcessEvent(*key_event);
100+
};
101+
m_tokens.push_back(
102+
{EventNotifier::Get()->AddEventTypeFilter(wxEVT_KEY_DOWN, std::move(on_key_down)), wxEVT_KEY_DOWN});
103+
m_tokens.push_back(
104+
{EventNotifier::Get()->AddEventTypeFilter(wxEVT_CHAR_HOOK, std::move(on_char_hook)), wxEVT_CHAR_HOOK});
80105
}
81106

82107
clBuiltinTerminalPane::~clBuiltinTerminalPane()
83108
{
109+
for (const auto& [token, evt_type] : m_tokens) {
110+
EventNotifier::Get()->RemoveEventTypeFilter(evt_type, token);
111+
}
112+
84113
m_book->Unbind(wxEVT_BOOK_PAGE_CHANGED, &clBuiltinTerminalPane::OnPageChanged, this);
85114
EventNotifier::Get()->Unbind(wxEVT_WORKSPACE_LOADED, &clBuiltinTerminalPane::OnWorkspaceLoaded, this);
86115
clConfig::Get().Write("terminal/last_used_terminal", m_terminal_types->GetStringSelection());
@@ -115,7 +144,6 @@ void clBuiltinTerminalPane::OnNew(wxCommandEvent& event)
115144
// By default, inherit parent's env.
116145
EnvSetter env_setter{};
117146
std::optional<TerminalView::EnvironmentList> env{std::nullopt};
118-
119147
TerminalView* ctrl = new TerminalView(m_book, cmd, env);
120148
m_book->AddPage(ctrl, cmd, true);
121149
m_book->SetPageToolTip(m_book->GetPageCount() - 1, cmd);

Plugin/wxTerminalCtrl/clBuiltinTerminalPane.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
#include "Notebook.h"
55
#include "clWorkspaceEvent.hpp"
6+
#include "event_notifier.h"
67
#include "terminal_event.h"
78

9+
#include <vector>
810
#include <wx/aui/auibar.h>
911
#include <wx/choice.h>
1012
#include <wx/panel.h>
@@ -34,6 +36,7 @@ class WXDLLIMPEXP_SDK clBuiltinTerminalPane : public wxPanel
3436
wxAuiToolBar* m_toolbar = nullptr;
3537
Notebook* m_book = nullptr;
3638
wxChoice* m_terminal_types = nullptr;
39+
std::vector<std::pair<EventFilterCallbackToken, wxEventType>> m_tokens;
3740
};
3841

3942
#endif // CLBUILTINTERMINALPANE_HPP

submodules/wxTerminalEmulator

0 commit comments

Comments
 (0)