mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 10:37:41 +00:00
LibLine: Use Core::EventLoop for outer read loop
This commit changes LibLine's internal structure to work in an event loop, and as a result, also switches it to being a Core::Object.
This commit is contained in:
parent
8e6df3949d
commit
70a213a6ec
7 changed files with 583 additions and 517 deletions
|
@ -44,7 +44,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static Line::Editor editor {};
|
RefPtr<Line::Editor> editor;
|
||||||
|
|
||||||
OwnPtr<DebugSession> g_debug_session;
|
OwnPtr<DebugSession> g_debug_session;
|
||||||
|
|
||||||
|
@ -173,6 +173,8 @@ void print_help()
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
editor = Line::Editor::construct();
|
||||||
|
|
||||||
if (pledge("stdio proc exec rpath tty sigaction", nullptr) < 0) {
|
if (pledge("stdio proc exec rpath tty sigaction", nullptr) < 0) {
|
||||||
perror("pledge");
|
perror("pledge");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -236,7 +238,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto command_result = editor.get_line("(sdb) ");
|
auto command_result = editor->get_line("(sdb) ");
|
||||||
|
|
||||||
if (command_result.is_error())
|
if (command_result.is_error())
|
||||||
return DebugSession::DebugDecision::Detach;
|
return DebugSession::DebugDecision::Detach;
|
||||||
|
@ -246,8 +248,8 @@ int main(int argc, char** argv)
|
||||||
bool success = false;
|
bool success = false;
|
||||||
Optional<DebugSession::DebugDecision> decision;
|
Optional<DebugSession::DebugDecision> decision;
|
||||||
|
|
||||||
if (command.is_empty() && !editor.history().is_empty()) {
|
if (command.is_empty() && !editor->history().is_empty()) {
|
||||||
command = editor.history().last();
|
command = editor->history().last();
|
||||||
}
|
}
|
||||||
if (command == "cont") {
|
if (command == "cont") {
|
||||||
decision = DebugSession::DebugDecision::Continue;
|
decision = DebugSession::DebugDecision::Continue;
|
||||||
|
@ -276,8 +278,8 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
if (success && !command.is_empty()) {
|
if (success && !command.is_empty()) {
|
||||||
// Don't add repeated commands to history
|
// Don't add repeated commands to history
|
||||||
if (editor.history().is_empty() || editor.history().last() != command)
|
if (editor->history().is_empty() || editor->history().last() != command)
|
||||||
editor.add_to_history(command);
|
editor->add_to_history(command);
|
||||||
}
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
print_help();
|
print_help();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -38,6 +38,8 @@
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibCore/DirIterator.h>
|
#include <LibCore/DirIterator.h>
|
||||||
|
#include <LibCore/Notifier.h>
|
||||||
|
#include <LibCore/Object.h>
|
||||||
#include <LibLine/Span.h>
|
#include <LibLine/Span.h>
|
||||||
#include <LibLine/Style.h>
|
#include <LibLine/Style.h>
|
||||||
#include <LibLine/SuggestionDisplay.h>
|
#include <LibLine/SuggestionDisplay.h>
|
||||||
|
@ -82,7 +84,9 @@ struct Configuration {
|
||||||
OperationMode operation_mode { OperationMode::Full };
|
OperationMode operation_mode { OperationMode::Full };
|
||||||
};
|
};
|
||||||
|
|
||||||
class Editor {
|
class Editor : public Core::Object {
|
||||||
|
C_OBJECT(Editor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class Error {
|
enum class Error {
|
||||||
ReadFailure,
|
ReadFailure,
|
||||||
|
@ -90,7 +94,6 @@ public:
|
||||||
Eof,
|
Eof,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Editor(Configuration configuration = {});
|
|
||||||
~Editor();
|
~Editor();
|
||||||
|
|
||||||
Result<String, Error> get_line(const String& prompt);
|
Result<String, Error> get_line(const String& prompt);
|
||||||
|
@ -160,6 +163,8 @@ public:
|
||||||
bool is_editing() const { return m_is_editing; }
|
bool is_editing() const { return m_is_editing; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit Editor(Configuration configuration = {});
|
||||||
|
|
||||||
struct KeyCallback {
|
struct KeyCallback {
|
||||||
KeyCallback(Function<bool(Editor&)> cb)
|
KeyCallback(Function<bool(Editor&)> cb)
|
||||||
: callback(move(cb))
|
: callback(move(cb))
|
||||||
|
@ -168,6 +173,8 @@ private:
|
||||||
Function<bool(Editor&)> callback;
|
Function<bool(Editor&)> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void handle_read_event();
|
||||||
|
|
||||||
Vector<size_t, 2> vt_dsr();
|
Vector<size_t, 2> vt_dsr();
|
||||||
void remove_at_index(size_t);
|
void remove_at_index(size_t);
|
||||||
|
|
||||||
|
@ -208,6 +215,7 @@ private:
|
||||||
m_prompt_lines_at_suggestion_initiation = 0;
|
m_prompt_lines_at_suggestion_initiation = 0;
|
||||||
m_refresh_needed = true;
|
m_refresh_needed = true;
|
||||||
m_input_error.clear();
|
m_input_error.clear();
|
||||||
|
m_returned_line = String::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh_display();
|
void refresh_display();
|
||||||
|
@ -266,7 +274,7 @@ private:
|
||||||
|
|
||||||
bool m_finish { false };
|
bool m_finish { false };
|
||||||
|
|
||||||
OwnPtr<Editor> m_search_editor;
|
RefPtr<Editor> m_search_editor;
|
||||||
bool m_is_searching { false };
|
bool m_is_searching { false };
|
||||||
bool m_reset_buffer_on_search_end { true };
|
bool m_reset_buffer_on_search_end { true };
|
||||||
size_t m_search_offset { 0 };
|
size_t m_search_offset { 0 };
|
||||||
|
@ -278,6 +286,7 @@ private:
|
||||||
ByteBuffer m_pending_chars;
|
ByteBuffer m_pending_chars;
|
||||||
Vector<char, 512> m_incomplete_data;
|
Vector<char, 512> m_incomplete_data;
|
||||||
Optional<Error> m_input_error;
|
Optional<Error> m_input_error;
|
||||||
|
String m_returned_line;
|
||||||
|
|
||||||
size_t m_cursor { 0 };
|
size_t m_cursor { 0 };
|
||||||
size_t m_drawn_cursor { 0 };
|
size_t m_drawn_cursor { 0 };
|
||||||
|
@ -336,6 +345,8 @@ private:
|
||||||
HashMap<u32, HashMap<u32, Style>> m_anchored_spans_starting;
|
HashMap<u32, HashMap<u32, Style>> m_anchored_spans_starting;
|
||||||
HashMap<u32, HashMap<u32, Style>> m_anchored_spans_ending;
|
HashMap<u32, HashMap<u32, Style>> m_anchored_spans_ending;
|
||||||
|
|
||||||
|
RefPtr<Core::Notifier> m_notifier;
|
||||||
|
|
||||||
bool m_initialized { false };
|
bool m_initialized { false };
|
||||||
bool m_refresh_needed { false };
|
bool m_refresh_needed { false };
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
// if we want to be more sh-like, we should do that some day
|
// if we want to be more sh-like, we should do that some day
|
||||||
static constexpr bool HighlightVariablesInsideStrings = false;
|
static constexpr bool HighlightVariablesInsideStrings = false;
|
||||||
static bool s_disable_hyperlinks = false;
|
static bool s_disable_hyperlinks = false;
|
||||||
extern Line::Editor editor;
|
extern RefPtr<Line::Editor> editor;
|
||||||
|
|
||||||
//#define SH_DEBUG
|
//#define SH_DEBUG
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ String Shell::prompt() const
|
||||||
};
|
};
|
||||||
|
|
||||||
auto the_prompt = build_prompt();
|
auto the_prompt = build_prompt();
|
||||||
auto prompt_length = editor.actual_rendered_string_length(the_prompt);
|
auto prompt_length = editor->actual_rendered_string_length(the_prompt);
|
||||||
|
|
||||||
if (m_should_continue != ExitCodeOrContinuationRequest::Nothing) {
|
if (m_should_continue != ExitCodeOrContinuationRequest::Nothing) {
|
||||||
const auto format_string = "\033[34m%.*-s\033[m";
|
const auto format_string = "\033[34m%.*-s\033[m";
|
||||||
|
@ -511,8 +511,8 @@ int Shell::builtin_disown(int argc, const char** argv)
|
||||||
|
|
||||||
int Shell::builtin_history(int, const char**)
|
int Shell::builtin_history(int, const char**)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < editor.history().size(); ++i) {
|
for (size_t i = 0; i < editor->history().size(); ++i) {
|
||||||
printf("%6zu %s\n", i, editor.history()[i].characters());
|
printf("%6zu %s\n", i, editor->history()[i].characters());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1385,7 +1385,7 @@ void Shell::load_history()
|
||||||
while (history_file->can_read_line()) {
|
while (history_file->can_read_line()) {
|
||||||
auto b = history_file->read_line(1024);
|
auto b = history_file->read_line(1024);
|
||||||
// skip the newline and terminating bytes
|
// skip the newline and terminating bytes
|
||||||
editor.add_to_history(String(reinterpret_cast<const char*>(b.data()), b.size() - 2));
|
editor->add_to_history(String(reinterpret_cast<const char*>(b.data()), b.size() - 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,7 +1395,7 @@ void Shell::save_history()
|
||||||
if (file_or_error.is_error())
|
if (file_or_error.is_error())
|
||||||
return;
|
return;
|
||||||
auto& file = *file_or_error.value();
|
auto& file = *file_or_error.value();
|
||||||
for (const auto& line : editor.history()) {
|
for (const auto& line : editor->history()) {
|
||||||
file.write(line);
|
file.write(line);
|
||||||
file.write("\n");
|
file.write("\n");
|
||||||
}
|
}
|
||||||
|
@ -1484,7 +1484,7 @@ void Shell::cache_path()
|
||||||
quick_sort(cached_path);
|
quick_sort(cached_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::highlight(Line::Editor&) const
|
void Shell::highlight(Line::Editor& editor) const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
if (m_should_continue == ExitCodeOrContinuationRequest::DoubleQuotedString) {
|
if (m_should_continue == ExitCodeOrContinuationRequest::DoubleQuotedString) {
|
||||||
|
@ -1703,7 +1703,7 @@ Vector<Line::CompletionSuggestion> Shell::complete(const Line::Editor& editor)
|
||||||
|
|
||||||
bool Shell::read_single_line()
|
bool Shell::read_single_line()
|
||||||
{
|
{
|
||||||
auto line_result = editor.get_line(prompt());
|
auto line_result = editor->get_line(prompt());
|
||||||
|
|
||||||
if (line_result.is_error()) {
|
if (line_result.is_error()) {
|
||||||
m_complete_line_builder.clear();
|
m_complete_line_builder.clear();
|
||||||
|
@ -1737,7 +1737,7 @@ bool Shell::read_single_line()
|
||||||
if (!complete_or_exit_code.has_value())
|
if (!complete_or_exit_code.has_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
editor.add_to_history(m_complete_line_builder.build());
|
editor->add_to_history(m_complete_line_builder.build());
|
||||||
m_complete_line_builder.clear();
|
m_complete_line_builder.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
Line::Editor editor { Line::Configuration { Line::Configuration::UnescapedSpaces } };
|
RefPtr<Line::Editor> editor;
|
||||||
Shell* s_shell;
|
Shell* s_shell;
|
||||||
|
|
||||||
void FileDescriptionCollector::collect()
|
void FileDescriptionCollector::collect()
|
||||||
|
@ -58,13 +58,13 @@ void FileDescriptionCollector::add(int fd)
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
Core::EventLoop loop;
|
Core::EventLoop loop;
|
||||||
|
|
||||||
signal(SIGINT, [](int) {
|
signal(SIGINT, [](int) {
|
||||||
editor.interrupted();
|
editor->interrupted();
|
||||||
});
|
});
|
||||||
|
|
||||||
signal(SIGWINCH, [](int) {
|
signal(SIGWINCH, [](int) {
|
||||||
editor.resized();
|
editor->resized();
|
||||||
});
|
});
|
||||||
|
|
||||||
signal(SIGHUP, [](int) {
|
signal(SIGHUP, [](int) {
|
||||||
|
@ -92,18 +92,20 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor = Line::Editor::construct(Line::Configuration { Line::Configuration::UnescapedSpaces });
|
||||||
|
|
||||||
auto shell = Shell::construct();
|
auto shell = Shell::construct();
|
||||||
s_shell = shell.ptr();
|
s_shell = shell.ptr();
|
||||||
|
|
||||||
editor.initialize();
|
editor->initialize();
|
||||||
shell->termios = editor.termios();
|
shell->termios = editor->termios();
|
||||||
shell->default_termios = editor.default_termios();
|
shell->default_termios = editor->default_termios();
|
||||||
|
|
||||||
editor.on_display_refresh = [&](auto& editor) {
|
editor->on_display_refresh = [&](auto& editor) {
|
||||||
editor.strip_styles();
|
editor.strip_styles();
|
||||||
shell->highlight(editor);
|
shell->highlight(editor);
|
||||||
};
|
};
|
||||||
editor.on_tab_complete = [&](const Line::Editor& editor) {
|
editor->on_tab_complete = [&](const Line::Editor& editor) {
|
||||||
return shell->complete(editor);
|
return shell->complete(editor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,13 +130,15 @@ int main(int argc, char** argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.on_interrupt_handled = [&] {
|
editor->on_interrupt_handled = [&] {
|
||||||
if (!shell->should_read_more()) {
|
if (!shell->should_read_more()) {
|
||||||
shell->finish_command();
|
shell->finish_command();
|
||||||
editor.finish();
|
editor->finish();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
shell->add_child(*editor);
|
||||||
|
|
||||||
Core::EventLoop::current().post_event(*shell, make<Core::CustomEvent>(Shell::ShellEventType::ReadLine));
|
Core::EventLoop::current().post_event(*shell, make<Core::CustomEvent>(Shell::ShellEventType::ReadLine));
|
||||||
|
|
||||||
return loop.exec();
|
return loop.exec();
|
||||||
|
|
|
@ -65,7 +65,7 @@ private:
|
||||||
|
|
||||||
static bool s_dump_ast = false;
|
static bool s_dump_ast = false;
|
||||||
static bool s_print_last_result = false;
|
static bool s_print_last_result = false;
|
||||||
static OwnPtr<Line::Editor> s_editor;
|
static RefPtr<Line::Editor> s_editor;
|
||||||
static int s_repl_line_level = 0;
|
static int s_repl_line_level = 0;
|
||||||
static bool s_fail_repl = false;
|
static bool s_fail_repl = false;
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ int main(int argc, char** argv)
|
||||||
if (test_mode)
|
if (test_mode)
|
||||||
enable_test_mode(*interpreter);
|
enable_test_mode(*interpreter);
|
||||||
|
|
||||||
s_editor = make<Line::Editor>();
|
s_editor = Line::Editor::construct();
|
||||||
|
|
||||||
signal(SIGINT, [](int) {
|
signal(SIGINT, [](int) {
|
||||||
if (!s_editor->is_editing())
|
if (!s_editor->is_editing())
|
||||||
|
|
|
@ -110,10 +110,9 @@ Core::EventLoop loop;
|
||||||
int run(Function<void(const char*, size_t)> fn)
|
int run(Function<void(const char*, size_t)> fn)
|
||||||
{
|
{
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
Line::Editor editor;
|
auto editor = Line::Editor::construct();
|
||||||
editor.initialize();
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto line_result = editor.get_line("> ");
|
auto line_result = editor->get_line("> ");
|
||||||
|
|
||||||
if (line_result.is_error())
|
if (line_result.is_error())
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue