elna/shell/state.cpp

215 lines
5.5 KiB
C++

#include "elna/state.hpp"
namespace elna
{
std::string cursor_to_column(const std::uint16_t position)
{
std::string code = std::to_string(position);
code.insert(0, "\x1b[");
code.push_back('G');
return code;
}
key::key()
: store(static_cast<unsigned char>(0x1b))
{
}
key::key(const unsigned char c, const std::uint8_t modifiers)
: store(c), modifiers(modifiers == 0 ? 0 : modifiers - 1)
{
}
key::key(const unsigned char c, const modifier modifiers)
: store(c), modifiers(static_cast<uint8_t>(modifiers))
{
}
key::key(const special_key control, const std::uint8_t modifiers)
: store(control), modifiers(modifiers == 0 ? 0 : modifiers - 1)
{
}
key::key(const special_key control, const modifier modifiers)
: store(control), modifiers(static_cast<uint8_t>(modifiers))
{
}
unsigned char key::character() const
{
return std::get<unsigned char>(this->store);
}
special_key key::control() const
{
return std::get<special_key>(this->store);
}
bool key::modified(const std::uint8_t modifiers) const noexcept
{
return this->modifiers == modifiers;
}
bool key::modified(const modifier modifiers) const noexcept
{
return this->modifiers == static_cast<std::uint8_t>(modifiers);
}
bool key::operator==(const unsigned char c) const
{
return std::holds_alternative<unsigned char>(this->store)
&& std::get<unsigned char>(this->store) == c;
}
bool key::operator==(const special_key control) const
{
return std::holds_alternative<special_key>(this->store)
&& std::get<special_key>(this->store) == control;
}
bool key::operator==(const key& that) const
{
return this->store == that.store;
}
bool key::operator!=(const unsigned char c) const
{
return !(*this == c);
}
bool key::operator!=(const special_key control) const
{
return !(*this == control);
}
bool key::operator!=(const key& that) const
{
return !(*this == that);
}
bool key::is_character() const noexcept
{
return std::holds_alternative<unsigned char>(this->store);
}
bool key::is_control() const noexcept
{
return std::holds_alternative<special_key>(this->store);
}
bool key::empty() const noexcept
{
return *this == '\x1b';
}
bool operator==(const special_key control, const key& that)
{
return that == control;
}
bool operator==(const char c, const key& that)
{
return that == c;
}
bool operator!=(const special_key control, const key& that)
{
return that != control;
}
bool operator!=(const char c, const key& that)
{
return that != c;
}
editor_state::editor_state()
{
this->input.reserve(1024);
}
void editor_state::load(const std::string& text)
{
this->input = text;
}
const std::string& editor_state::command_line() const noexcept
{
return this->input;
}
std::size_t editor_state::absolute_position() const noexcept
{
return this->prompt.size() + this->position;
}
void editor_state::insert(const std::string& text)
{
this->input.insert(std::end(this->input), std::cbegin(text), std::cend(text));
}
action editor_state::process_keypress(const key& press)
{
if (press.is_control())
{
switch (press.control())
{
case special_key::arrow_left:
if (this->position > 1)
{
--this->position;
}
return action::move;
case special_key::arrow_right:
if (this->position + 1 < this->input.size() + this->prompt.size())
{
++this->position;
}
return action::move;
case special_key::arrow_up:
case special_key::arrow_down:
return action::history;
case special_key::home_key:
this->position = 1;
return action::move;
case special_key::end_key:
this->position = this->input.size() + 1;
return action::move;
default:
return action::ignore;
}
}
else if (press.modified(modifier::ctrl))
{
switch (press.character())
{
case 'd':
return action::finalize;
case 't':
return action::complete;
default:
return action::ignore;
}
}
else
{
switch (press.character())
{
case 127: // Backspace.
if (this->position <= this->input.size() + 1 && this->position > 1)
{
--this->position;
this->input.erase(this->position - 1, 1);
}
return action::redraw;
case '\r':
return action::finalize;
default:
++this->position;
this->input.push_back(press.character());
return action::write;
}
}
}
}