215 lines
5.5 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|
|
}
|