ไลบรารี Editline (และ readline GNU) ทำงานได้เฉพาะกับความสามารถของเทอร์มินัล หากต้องการใช้ไลบรารีเหล่านี้กับคอนโซลในเกมของคุณคุณต้องใช้เทอร์มินัลอีมูเลเตอร์ (TTY) ก่อน
แทน (เนื่องจากการทำเช่นนั้นสำหรับเกมจะบ้า) ฉันขอแนะนำให้คุณใช้การเคลื่อนไหวของเคอร์เซอร์และแก้ไขด้วยตัวเอง ฉันเคยเขียนคลาส C ++ เพื่อจัดการสิ่งนี้สำหรับคอนโซลในเกมของฉันเพื่อจุดประสงค์นี้ คลาสนี้มีชื่อว่า aptly EditLine ชั้นเรียนจัดการการเคลื่อนไหวของเคอร์เซอร์พื้นฐานลบไปข้างหน้า / ถอยหลังลบ / คำ / บรรทัดและประวัติ ไม่มีอะไรแฟนซี แต่คุณอาจพบว่ามีประโยชน์ เอกสารนั้นกระจัดกระจายหรือไม่มีอยู่หวังว่าคุณจะสามารถเข้าใจได้ ไม่มีการทำให้สมบูรณ์อัตโนมัติน่าเสียดาย ฉันใช้งานชั้นบนโดยใช้คลาสนี้
editline.h
#include <string>
#include <vector>
class EditLine {
public:
EditLine();
EditLine(const EditLine&);
~EditLine();
// assignment operator
EditLine& operator=(const EditLine&);
// comparison operators
bool operator==(const EditLine&) const;
bool operator!=(const EditLine&) const;
// edit commands
void accept_line();
void reject_line();
void insert_char(int);
void delete_char();
void backward_delete_char();
void delete_word();
void backward_delete_word();
void delete_line();
// motion commands
void beginning_of_line();
void end_of_line();
void forward_char();
void backward_char();
void forward_word();
void backward_word();
// history commands
void next_history();
void previous_history();
// accessors
int history_pos() const;
inline size_t history_size() const;
inline bool empty() const;
inline const std::string& line() const;
inline size_t length() const;
inline const std::string::size_type& cursor_pos() const;
// mutators
void set_line(const std::string& s);
void set_cursor_pos(std::string::size_type);
void reset_line();
private:
std::string line_;
std::string::size_type cursor_pos_;
std::vector< std::string > history_;
std::vector< std::string >::iterator last_iter_;
};
inline size_t EditLine::history_size() const { return history_.size(); }
inline const std::string& EditLine::line() const { return line_; }
inline const std::string::size_type& EditLine::cursor_pos() const { return cursor_pos_; }
inline bool EditLine::empty() const { return line_.empty(); }
inline size_t EditLine::length() const { return line_.length(); }
editline.cpp
#include "editline.h"
#include "string_utils.h"
#include <string>
namespace {
const std::string word_delims = " !@#$%^&*()+-={}[]:\"|;'\\<>?,./";
} // namespace
EditLine::EditLine()
: line_(std::string()),
cursor_pos_(0),
last_iter_(history_.end())
{
}
EditLine::EditLine(const EditLine& rhs)
{
*this = rhs;
}
EditLine::~EditLine()
{
}
EditLine& EditLine::operator=(const EditLine& rhs)
{
line_ = rhs.line_;
cursor_pos_ = rhs.cursor_pos_;
history_ = rhs.history_;
if (rhs.last_iter_ == rhs.history_.end())
last_iter_ = history_.end();
else {
last_iter_ = history_.begin();
std::advance(last_iter_, rhs.last_iter_ - rhs.history_.begin());
}
return *this;
}
void EditLine::set_line(const std::string& s)
{
line_ = s;
cursor_pos_ = line_.size();
}
void EditLine::set_cursor_pos(std::string::size_type pos)
{
if (pos > line_.size())
pos = line_.size();
cursor_pos_ = pos;
}
void EditLine::reset_line()
{
line_.clear();
cursor_pos_ = 0;
}
bool EditLine::operator==(const EditLine& rhs) const
{
return (line_ == rhs.line_ &&
cursor_pos_ == rhs.cursor_pos_ &&
history_ == rhs.history_ &&
history_pos() == rhs.history_pos());
}
bool EditLine::operator!=(const EditLine& rhs) const
{
return !operator==(rhs);
}
void EditLine::accept_line()
{
if (!line_.empty())
history_.push_back(line_);
line_.clear();
cursor_pos_ = 0;
last_iter_ = history_.end();
}
void EditLine::reject_line()
{
line_.clear();
cursor_pos_ = 0;
last_iter_ = history_.end();
}
void EditLine::insert_char(int c)
{
line_.insert(cursor_pos_, 1, c);
cursor_pos_++;
}
void EditLine::delete_char()
{
line_.erase(cursor_pos_, 1);
}
void EditLine::backward_delete_char()
{
if (cursor_pos_ > 0) {
line_.erase(cursor_pos_ - 1, 1);
cursor_pos_--;
}
}
void EditLine::delete_word()
{
std::string::size_type pos;
// check if cursor points on a word delim
if (word_delims.find(line_[cursor_pos_]) != std::string::npos) {
// cursor points on a word delim - remove everything from here to
// right up to first delim after this word.
pos = line_.find_first_not_of(word_delims, cursor_pos_+1);
if (pos != std::string::npos)
pos = line_.find_first_of(word_delims, pos+1);
} else {
// cursor is in the middle of a word - remove everything up to first
// delim.
pos = line_.find_first_of(word_delims, cursor_pos_+1);
}
if (pos != std::string::npos)
// removes everything right of cursor up to 'pos'
line_.replace(cursor_pos_, pos - cursor_pos_, "");
else
// removes everthing right of cursor
line_.erase(cursor_pos_);
}
void EditLine::backward_delete_word()
{
std::string::size_type pos;
if (cursor_pos_ == 0) return;
// check if char left of cursor is a word delim
if (word_delims.find(line_[cursor_pos_-1]) != std::string::npos) {
// left of cursor is a word delim - remove everything from left of
// cursor up to next word delim before current word.
pos = rfind_first_not_of(line_, word_delims, cursor_pos_-1);
if (pos != std::string::npos)
pos = rfind_first_of(line_, word_delims, pos);
} else {
// left of cursor is not a word delim - remove everything left of
// cursor up to next word delim.
pos = rfind_first_of(line_, word_delims, cursor_pos_-1);
}
if (pos != std::string::npos) {
// removes from right of pos and up to cursor
line_.erase(pos + 1, cursor_pos_ - pos - 1);
cursor_pos_ = pos + 1;
} else {
// removes everything from beginning up to cursor
line_.erase(0, cursor_pos_);
cursor_pos_ = 0;
}
}
void EditLine::delete_line()
{
line_.erase(cursor_pos_);
cursor_pos_ = line_.size();
}
void EditLine::beginning_of_line()
{
cursor_pos_ = 0;
}
void EditLine::end_of_line()
{
cursor_pos_ = line_.size();
}
void EditLine::forward_char()
{
if (cursor_pos_ < line_.size())
cursor_pos_++;
}
void EditLine::backward_char()
{
if (cursor_pos_ > 0)
cursor_pos_--;
}
void EditLine::forward_word()
{
std::string::size_type pos;
pos = line_.find_first_of(word_delims, cursor_pos_);
if (pos != std::string::npos)
cursor_pos_ = pos + 1;
else
cursor_pos_ = line_.size();
}
void EditLine::backward_word()
{
if (cursor_pos_ <= 1) {
cursor_pos_ = 0;
return;
}
std::string::size_type pos, cursor_pos;
cursor_pos = cursor_pos_;
if (cursor_pos >= 2)
cursor_pos -= 2;
bool found = false;
for (int i = (int) cursor_pos; i >= 0; --i) {
if (word_delims.find(line_[i]) != std::string::npos) {
pos = (std::string::size_type) i;
found = true;
break;
}
}
if (found)
cursor_pos_ = pos + 1;
else
cursor_pos_ = 0;
}
void EditLine::next_history()
{
if (!history_.empty()) {
if (last_iter_ == history_.end() || ++last_iter_ == history_.end())
last_iter_ = history_.begin();
line_ = *last_iter_;
cursor_pos_ = line_.size();
}
}
void EditLine::previous_history()
{
if (!history_.empty()) {
if (last_iter_ != history_.begin())
--last_iter_;
else
last_iter_ = --history_.end();
line_ = *last_iter_;
cursor_pos_ = line_.size();
}
}
int EditLine::history_pos() const
{
if (last_iter_ == history_.end())
return -1;
return last_iter_ - history_.begin();
}
string_utils.h
std::string::size_type rfind_first_not_of(const std::string& s,
const std::string& delims,
std::string::size_type pos);
std::string::size_type rfind_first_of(const std::string& s,
const std::string& delims,
std::string::size_type pos);
string_utils.cpp
std::string::size_type rfind_first_not_of(const std::string& s,
const std::string& delims, std::string::size_type pos)
{
std::string::size_type p = pos;
while (delims.find(s[p]) != std::string::npos) {
if (p == 0) // not found
return std::string::npos;
--p;
}
return p;
}
std::string::size_type rfind_first_of(const std::string& s,
const std::string& delims, std::string::size_type pos)
{
std::string::size_type p = pos;
while (delims.find(s[p]) == std::string::npos) {
if (p == 0) // not found
return std::string::npos;
--p;
}
return p;
}