Kernel: Add partial support for shell
We don't handle arrow keys, and the tty does not know how to clear the screeen :D
This commit is contained in:
parent
db076058b9
commit
a423cd8bb3
|
@ -19,10 +19,9 @@ namespace Kernel
|
|||
void rerender_buffer() const;
|
||||
BAN::Vector<BAN::String> parse_arguments(BAN::StringView) const;
|
||||
BAN::ErrorOr<void> process_command(const BAN::Vector<BAN::String>&);
|
||||
void key_event_callback(Input::KeyEvent);
|
||||
BAN::ErrorOr<void> update_prompt();
|
||||
|
||||
private:
|
||||
private:
|
||||
BAN::Vector<BAN::String> m_old_buffer;
|
||||
BAN::Vector<BAN::String> m_buffer;
|
||||
BAN::String m_prompt_string;
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace Kernel
|
|||
void render_from_buffer(uint32_t x, uint32_t y);
|
||||
|
||||
void on_key(Input::KeyEvent);
|
||||
void do_backspace();
|
||||
|
||||
private:
|
||||
enum class State
|
||||
|
|
|
@ -11,11 +11,23 @@
|
|||
#include <kernel/RTC.h>
|
||||
#include <kernel/Shell.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TTY_PRINT(...) \
|
||||
do { \
|
||||
BAN::String message_ = BAN::String::formatted(__VA_ARGS__); \
|
||||
MUST(Process::current()->write(STDOUT_FILENO, message_.data(), message_.size())); \
|
||||
} while (false)
|
||||
|
||||
#define TTY_PRINTLN(...) \
|
||||
do { \
|
||||
TTY_PRINT(__VA_ARGS__); \
|
||||
MUST(Process::current()->write(STDOUT_FILENO, "\n", 1)); \
|
||||
} while (false)
|
||||
|
||||
|
||||
#define TTY_PRINT(...)
|
||||
#define TTY_PRINTLN(...)
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -99,17 +111,22 @@ namespace Kernel
|
|||
|
||||
void Shell::run()
|
||||
{
|
||||
int fd = MUST(Process::current()->open("/dev/tty1"sv, O_RDONLY));
|
||||
|
||||
TTY_PRINT("{}", m_prompt);
|
||||
BAN::String input;
|
||||
for (;;)
|
||||
{
|
||||
uint8_t buffer[128];
|
||||
size_t n_read = MUST(Process::current()->read(fd, buffer, sizeof(buffer)));
|
||||
dprintln("{}", BAN::StringView((const char*)buffer, n_read));
|
||||
//Input::KeyEvent event;
|
||||
//MUST(Process::current()->read(fd, &event, sizeof(event)));
|
||||
//key_event_callback(event);
|
||||
char buffer[128];
|
||||
size_t n_read = MUST(Process::current()->read(STDIN_FILENO, buffer, sizeof(buffer)));
|
||||
|
||||
MUST(input.append(BAN::StringView(buffer, n_read)));
|
||||
if (input.back() == '\n')
|
||||
{
|
||||
input.pop_back();
|
||||
if (auto res = process_command(parse_arguments(input)); res.is_error())
|
||||
TTY_PRINTLN("{}", res.error());
|
||||
TTY_PRINT("{}", m_prompt);
|
||||
input.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,147 +557,4 @@ argument_done:
|
|||
TTY_PRINT("\e[{}G{}\e[K", m_prompt_length + 1, m_buffer[m_cursor_pos.line]);
|
||||
}
|
||||
|
||||
static uint32_t get_last_length(BAN::StringView sv)
|
||||
{
|
||||
if (sv.size() >= 2 && ((uint8_t)sv[sv.size() - 2] >> 5) == 0b110) return 2;
|
||||
if (sv.size() >= 3 && ((uint8_t)sv[sv.size() - 3] >> 4) == 0b1110) return 3;
|
||||
if (sv.size() >= 4 && ((uint8_t)sv[sv.size() - 4] >> 3) == 0b11110) return 4;
|
||||
return BAN::Math::min<uint32_t>(sv.size(), 1);
|
||||
}
|
||||
|
||||
static uint32_t get_next_length(BAN::StringView sv)
|
||||
{
|
||||
if (sv.size() >= 2 && ((uint8_t)sv[0] >> 5) == 0b110) return 2;
|
||||
if (sv.size() >= 3 && ((uint8_t)sv[0] >> 4) == 0b1110) return 3;
|
||||
if (sv.size() >= 4 && ((uint8_t)sv[0] >> 3) == 0b11110) return 4;
|
||||
return BAN::Math::min<uint32_t>(sv.size(), 1);
|
||||
}
|
||||
|
||||
static uint32_t get_unicode_character_count(BAN::StringView sv)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
for (uint32_t i = 0; i < sv.size(); i++)
|
||||
{
|
||||
uint8_t ch = sv[i];
|
||||
if ((ch >> 5) == 0b110) i += 1;
|
||||
if ((ch >> 4) == 0b1110) i += 2;
|
||||
if ((ch >> 3) == 0b11110) i += 3;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void Shell::key_event_callback(Input::KeyEvent event)
|
||||
{
|
||||
if (event.released())
|
||||
return;
|
||||
|
||||
BAN::String& current_buffer = m_buffer[m_cursor_pos.line];
|
||||
|
||||
switch (event.key)
|
||||
{
|
||||
case Input::Key::Backspace:
|
||||
if (m_cursor_pos.col > 0)
|
||||
{
|
||||
TTY_PRINT("\e[D{} ", current_buffer.sv().substring(m_cursor_pos.index));
|
||||
|
||||
uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index));
|
||||
m_cursor_pos.index -= len;
|
||||
current_buffer.erase(m_cursor_pos.index, len);
|
||||
m_cursor_pos.col--;
|
||||
}
|
||||
break;
|
||||
|
||||
case Input::Key::Enter:
|
||||
case Input::Key::NumpadEnter:
|
||||
{
|
||||
TTY_PRINTLN("");
|
||||
auto arguments = parse_arguments(current_buffer.sv());
|
||||
if (!arguments.empty())
|
||||
{
|
||||
if (auto res = process_command(arguments); res.is_error())
|
||||
TTY_PRINTLN("{}", res.error());
|
||||
MUST(m_old_buffer.push_back(current_buffer));
|
||||
m_buffer = m_old_buffer;
|
||||
MUST(m_buffer.push_back(""sv));
|
||||
m_cursor_pos.line = m_buffer.size() - 1;
|
||||
}
|
||||
m_cursor_pos.col = 0;
|
||||
m_cursor_pos.index = 0;
|
||||
TTY_PRINT("{}", m_prompt);
|
||||
break;
|
||||
}
|
||||
|
||||
case Input::Key::Escape:
|
||||
TTY_PRINTLN("time since boot {} ms", PIT::ms_since_boot());
|
||||
break;
|
||||
|
||||
case Input::Key::Tab:
|
||||
break;
|
||||
|
||||
case Input::Key::ArrowLeft:
|
||||
if (m_cursor_pos.index > 0)
|
||||
{
|
||||
uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index));
|
||||
m_cursor_pos.index -= len;
|
||||
m_cursor_pos.col--;
|
||||
}
|
||||
break;
|
||||
|
||||
case Input::Key::ArrowRight:
|
||||
if (m_cursor_pos.index < current_buffer.size())
|
||||
{
|
||||
uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index));
|
||||
m_cursor_pos.index += len;
|
||||
m_cursor_pos.col++;
|
||||
}
|
||||
break;
|
||||
|
||||
case Input::Key::ArrowUp:
|
||||
if (m_cursor_pos.line > 0)
|
||||
{
|
||||
const auto& new_buffer = m_buffer[m_cursor_pos.line - 1];
|
||||
m_cursor_pos.line--;
|
||||
m_cursor_pos.index = new_buffer.size();
|
||||
m_cursor_pos.col = get_unicode_character_count(new_buffer);
|
||||
rerender_buffer();
|
||||
}
|
||||
break;
|
||||
|
||||
case Input::Key::ArrowDown:
|
||||
if (m_cursor_pos.line < m_buffer.size() - 1)
|
||||
{
|
||||
const auto& new_buffer = m_buffer[m_cursor_pos.line + 1];
|
||||
m_cursor_pos.line++;
|
||||
m_cursor_pos.index = new_buffer.size();
|
||||
m_cursor_pos.col = get_unicode_character_count(new_buffer);
|
||||
rerender_buffer();
|
||||
}
|
||||
break;
|
||||
|
||||
case Input::Key::A:
|
||||
if (event.ctrl())
|
||||
{
|
||||
m_cursor_pos.col = m_cursor_pos.index = 0;
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
|
||||
default:
|
||||
{
|
||||
const char* utf8 = Input::key_event_to_utf8(event);
|
||||
if (utf8)
|
||||
{
|
||||
TTY_PRINT("{}{}", utf8, current_buffer.sv().substring(m_cursor_pos.index));
|
||||
MUST(current_buffer.insert(utf8, m_cursor_pos.index));
|
||||
m_cursor_pos.index += strlen(utf8);
|
||||
m_cursor_pos.col++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//TTY_PRINT("\e[{}G", (m_prompt_length + m_cursor_pos.col) % m_tty->width() + 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -92,6 +92,7 @@ namespace Kernel
|
|||
ansi = "\n";
|
||||
break;
|
||||
case Input::Key::Backspace:
|
||||
ansi = nullptr;
|
||||
if (m_output.bytes > 0)
|
||||
{
|
||||
// Multibyte UTF8
|
||||
|
@ -103,19 +104,20 @@ namespace Kernel
|
|||
ASSERT(m_output.bytes > 0);
|
||||
m_output.bytes--;
|
||||
}
|
||||
ansi = "\b \b";
|
||||
do_backspace();
|
||||
}
|
||||
// Control sequence
|
||||
else if (m_output.bytes >= 2 && m_output.buffer[m_output.bytes - 2] == '\e')
|
||||
{
|
||||
m_output.bytes -= 2;
|
||||
ansi = "\b\b \b\b";
|
||||
do_backspace();
|
||||
do_backspace();
|
||||
}
|
||||
// Ascii
|
||||
else
|
||||
{
|
||||
m_output.bytes--;
|
||||
ansi = "\b \b";
|
||||
do_backspace();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -156,6 +158,16 @@ namespace Kernel
|
|||
m_terminal_driver->clear(m_background);
|
||||
}
|
||||
|
||||
void TTY::do_backspace()
|
||||
{
|
||||
if (m_column > 0)
|
||||
{
|
||||
m_column--;
|
||||
putchar_at(' ', m_column, m_row);
|
||||
set_cursor_position(m_column, m_row);
|
||||
}
|
||||
}
|
||||
|
||||
void TTY::set_cursor_position(uint32_t x, uint32_t y)
|
||||
{
|
||||
static uint32_t last_x = -1;
|
||||
|
|
|
@ -222,25 +222,10 @@ static void init2(void* terminal_driver)
|
|||
ASSERT(tty1);
|
||||
DeviceManager::get().add_device(tty1);
|
||||
|
||||
MUST(Process::create_kernel(
|
||||
[](void*)
|
||||
{
|
||||
MUST(Process::current()->init_stdio());
|
||||
while (true)
|
||||
{
|
||||
char buffer[1024];
|
||||
int n_read = MUST(Process::current()->read(STDIN_FILENO, buffer, sizeof(buffer)));
|
||||
MUST(Process::current()->write(STDOUT_FILENO, buffer, n_read));
|
||||
dprintln("{} bytes", n_read);
|
||||
}
|
||||
}, nullptr
|
||||
));
|
||||
|
||||
return;
|
||||
|
||||
MUST(Process::create_kernel(
|
||||
[](void*)
|
||||
{
|
||||
MUST(Process::current()->init_stdio());
|
||||
Shell* shell = new Shell();
|
||||
ASSERT(shell);
|
||||
shell->run();
|
||||
|
|
Loading…
Reference in New Issue