文本编辑器:Linux下基于ncurses的C++文本编辑器(加州大学尔湾分校作业)

工程传送门

用codeblock写的

https://download.csdn.net/download/renzemingcsdn/19421843

效果

在这里插入图片描述

题目

很长一堆英文,题目图片放到文末,主要是大小写字母输入,常规的回车、换行、上下左右、光标移动到行首、行尾、删除整行、删除一个字符,还有撤销重做。

设计思路——命令模式

命令模式的资料一艘一大堆,在此不赘述,涉及撤销重做的,很明显用命令模式。

https://www.jianshu.com/p/1bf9c2c907e8

所有涉及的文件如图所示。
在这里插入图片描述
简述程序思路:
初始化图型显示什么的老师已经做好,每次执行命令后,刷新界面,学生需要完成对内容的维护。
NcursesEditorView是对ncurses的二次封装,每次执行刷新命令,调用modle类函数获取光标位置,每行文字等信息,而后执行刷新操作。KeypressInteractionReader是NcursesKeypressReader的上层接口,用于接收用户命令并实例化一个commond类。
Command.hpp是个虚基类,需要继承并补上command_my.cpp。
EditorModel类用于管理文字、错误信息和光标信息,并提供接口用于对文字操作,并返回光标位置和文字信息。
EditorModel中存在一个大循环,用于处理各个命令并保存command实例,通过维护两个栈,实现撤销重做功能。通过异常语法,返回错误信息。
BooEditLog是打印输出的,由于终端被界面占用了,所以向文件打印调试信息,linux里面用tail命令,在另一个终端输出显示。

代码

只列出与命令模式有关的代码。

EditorModel

EditorModel.hpp,维护并返回光标位置、错误信息和文本内容。其中,光标位置为整形,并从1开始;错误信息是一个string,文本信息是个vector,其中每个string代表真实文本的一行。

#ifndef EDITORMODEL_HPP
#define EDITORMODEL_HPP
#include <string>
#include <vector>
class Command;
class EditorModel
{
public:
    // Initializes the editor model.  Initially, the cursor is on
    // line 1 column 1 and there should be one empty line of text
    // in the editor.
    EditorModel();
    // Returns the line number where the cursor currently should reside.
    int cursorLine() const;
    // Returns the column number where the cursor currently should reside.
    int cursorColumn() const;
    void cursor_set(int x,int y);
    // Returns the number of lines of text currently in the editor.
    int lineCount() const;
    // Returns the text on the given line number.
    const std::string& line(int lineNumber) const;
    // Returns the error message that should be displayed currently.
    const std::string& currentErrorMessage() const;
    // Sets the error message that should be displayed currently.
    void setErrorMessage(const std::string& errorMessage);
    // Clears the error message that should be displayed currently.
    void clearErrorMessage();
    // add one letter in current cursor
    void add(char c);
    void add(std::string s);
    // huan hang
    void _MJ();
    void _K();
    void _L();
    void _U();
    void _O();
    void _Y();
    void _P();
    std::string _D();
    char _H();
    struct xy now_xy();
private:
    // Write declarations for any private member variables here.
    // Additionally, you can add any private member functions you'd like.
    std::vector<std::string> data;
    int cursor_x=1,cursor_y=1;
    std::string err_info;
};
#endif

EditorModel.cpp

#include <string>

#include "EditorModel.hpp"
#include "EditorException.hpp"
#include "BooEditLog.hpp"

EditorModel::EditorModel()
{
    data.clear();
    data.push_back(std::string());
}

int EditorModel::cursorLine() const
{
    return cursor_x;
}

int EditorModel::cursorColumn() const
{
    return cursor_y;
}

void EditorModel::cursor_set(int x,int y){
    cursor_x=x;
    cursor_y=y;
}

int EditorModel::lineCount() const
{
    return data.size();
}

const std::string& EditorModel::line(int lineNumber) const
{
    return data[lineNumber-1];
}

const std::string& EditorModel::currentErrorMessage() const
{
    return err_info;
}

void EditorModel::setErrorMessage(const std::string& errorMessage)
{
    err_info=errorMessage;
}

void EditorModel::clearErrorMessage()
{
    err_info="";
}

void EditorModel::add(char c)
{
    data[cursor_x-1].insert(cursor_y-1,std::string(1,c));
    cursor_y++;
}
void EditorModel::add(std::string s){
    data.insert(data.begin()+cursor_x-1,s);
}
void EditorModel::_MJ(){
    std::string tmp;
    if(cursor_y==data[cursor_x-1].size()+1)tmp="";
    else tmp=data[cursor_x-1].substr(cursor_y-1);
    data[cursor_x-1]=data[cursor_x-1].substr(0,cursor_y-1);
    data.insert(data.begin()+cursor_x,tmp);
    cursor_x++;
    cursor_y=1;
}
void EditorModel::_L(){
    cursor_x--;
    if(cursor_x==0) {
        cursor_x=1;
        throw(EditorException("up to top"));
    }
    if(cursor_y>data[cursor_x-1].size()) cursor_y=data[cursor_x-1].size()+1;
}
void EditorModel::_K(){
    cursor_x++;
    if(cursor_x>data.size()){
        cursor_x=data.size();
        throw(EditorException("down to button"));
    }
    if(cursor_y>data[cursor_x-1].size()) cursor_y=data[cursor_x-1].size()+1;
}
void EditorModel::_U(){
    if(cursor_y==1&&cursor_x==1){
        throw(EditorException("head"));
    }else{
        cursor_y--;
        if(cursor_y==0){
            cursor_x--;
            cursor_y=data[cursor_x-1].size()+1;
        }
    }
}
void EditorModel::_O(){
    if(cursor_x==data.size() && cursor_y==data[cursor_x-1].size()+1){
        throw(EditorException("tail"));
    }else{
        cursor_y++;
        if(cursor_y>data[cursor_x-1].size()+1) {
            cursor_y=1;
            cursor_x++;
        }
    }
}
void EditorModel::_Y(){
    cursor_y=1;
}
void EditorModel::_P(){
    cursor_y=data[cursor_x-1].size()+1;
}
char EditorModel::_H(){
    cursor_y--;
    if(cursor_y==0){
        cursor_x--;
        if(cursor_x<=0){
            cursor_y=1;
            cursor_x=1;
            throw(EditorException("no letter"));
            return 0;
        }else{
            cursor_y=data[cursor_x-1].size()+1;
            data[cursor_x-1]+=data[cursor_x];
            data.erase(data.begin()+cursor_x);
            return 1;
        }
    }else{
        char tmp=data[cursor_x-1][cursor_y-1];
        data[cursor_x-1].erase(data[cursor_x-1].begin()+cursor_y-1);
        return tmp;
    }
}
std::string EditorModel::_D(){
    std::string tmp;
    if(data.size()==1){
        tmp=data[0];
        data[0]="";
        cursor_x=1;
        cursor_y=1;
        return tmp;
    }else{
        tmp=data[cursor_x-1];
        data.erase(data.begin()+cursor_x-1);
        if(cursor_x>data.size())cursor_x=data.size();
        if(cursor_y>data[cursor_x-1].size()) cursor_y=data[cursor_x-1].size()+1;
        return tmp;
    }
}

KeypressInteractionReader

这里接收指令,并生成comman实例,返回给 ,区分输入的是ctrl+?还是纯字母。
KeypressInteractionReader.hpp

#ifndef KEYPRESSINTERACTIONREADER_HPP
#define KEYPRESSINTERACTIONREADER_HPP
#include "InteractionReader.hpp"
#include "KeypressReader.hpp"
class KeypressInteractionReader : public InteractionReader
{
public:
    explicit KeypressInteractionReader(KeypressReader& keypressReader)
        : keypressReader{keypressReader}
    {
    }
    Interaction nextInteraction() override;
private:
    KeypressReader& keypressReader;
};
#endif

KeypressInteractionReader.cpp,节省篇幅,只贴部分,字母输入的部分只写几个。

#include "KeypressInteractionReader.hpp"
#include "BooEditLog.hpp"
#include "commond_my.hpp"
#include "commond_my_1.hpp"
#include <string>
Interaction KeypressInteractionReader::nextInteraction()
{
    while (true)
    {
        Keypress keypress = keypressReader.nextKeypress();
        Command* cmd;
        if (keypress.ctrl())
        {
            // The user pressed a Ctrl key (e.g., Ctrl+X); react accordingly
            switch (keypress.code())
            {
            case 'L':
                 cmd=new Command__L;
                 return Interaction::command(cmd);
            case 'K':
                 cmd=new Command__K;
                 return Interaction::command(cmd);
                             }
        }
        else
        {
            // The user pressed a normal key (e.g., 'h') without holding
            // down Ctrl; react accordingly
            char tmp=keypress.code();
            switch (tmp)
            {
                case 'a':
                    cmd=new Command_a;
                    return Interaction::command(cmd);
                case 'b':
                    cmd=new Command_b;
                    return Interaction::command(cmd);
                }

        }

    }
}               

Command

command类的实例调用EditorModel中的函数进行操作,如有错误则抛出异常,在InteractionProcessor中被接收。
Command.hpp

#ifndef COMMAND_HPP
#define COMMAND_HPP
#include "EditorModel.hpp"

class Command
{
public:
    virtual ~Command() = default;
    virtual void execute(EditorModel& model) = 0;
    virtual void undo(EditorModel& model) = 0;
};
#endif

command_my.hpp节约篇幅,只写两个。

#ifndef COMMOND_MY_H_INCLUDED
#define COMMOND_MY_H_INCLUDED

#include <string>
#include "Command.hpp"
#include "EditorModel.hpp"
#include "BooEditLog.hpp"

class Command_a : public Command{
public:
    void execute(EditorModel& model) override;
    void undo(EditorModel& model) override;
};
class Command_b : public Command{
public:
    void execute(EditorModel& model) override;
    void undo(EditorModel& model) override;
};

command_my.cpp

#include "commond_my.hpp"
#include "EditorModel.hpp"
void  Command_a ::execute(EditorModel& model)
{
    model.add('a');
}
void  Command_a ::undo(EditorModel& model)
{
    model._H();
}

InteractionProcessor

一个大循环,维护两个栈,st_1中记录所有已经命令,用户按下键盘后,返回命令实例,执行execute函数,当发生撤销指令时,st_1栈顶元素弹出,执行undo,并压入st_2中。当发生重做指令时,st_2栈顶弹出,执行excute,并压入st_1。当有新命令来到时,清空st_2。
InteractionProcessor.hpp


#ifndef INTERACTIONPROCESSOR_HPP
#define INTERACTIONPROCESSOR_HPP
#include <stack>

#include "EditorModel.hpp"
#include "EditorView.hpp"
#include "InteractionReader.hpp"



class InteractionProcessor
{
public:
    InteractionProcessor(
        EditorModel& model, EditorView& view,
        InteractionReader& interactionReader)
        : model{model}, view{view}, interactionReader{interactionReader}
    {
    }

    void run();

private:
    EditorModel& model;
    EditorView& view;
    InteractionReader& interactionReader;

    std::stack<Command*> st_1;
    std::stack<Command*> st_2;
};
#endif

InteractionProcessor.cpp

#include <string>
#include "InteractionProcessor.hpp"
#include "EditorException.hpp"
#include "Interaction.hpp"
#include "BooEditLog.hpp"
// This function implements command execution, but does not handle "undo"
// and "redo"; you'll need to add that handling.

void InteractionProcessor::run()
{
    view.refresh();
    Command* command;
    while (true)
    {
        Interaction interaction = interactionReader.nextInteraction();

        if (interaction.type() == InteractionType::quit)
        {
            booEditLog("InteractionProcessor:do quit");
            break;
        }
        else if (interaction.type() == InteractionType::undo)
        {
            model.clearErrorMessage();
            if(!st_1.empty()){
                command=st_1.top();
                st_1.pop();
                booEditLog("InteractionProcessor:do undo");
                command->undo(model);
                st_2.push(command);
            }
            view.refresh();
        }
        else if (interaction.type() == InteractionType::redo)
        {
            booEditLog("InteractionProcessor:do redo");
            if(!st_2.empty()){
                command=st_2.top();
                st_2.pop();
                command->execute(model);
                st_1.push(command);
            }
            view.refresh();

        }
        else if (interaction.type() == InteractionType::command)
        {
            command = interaction.command();
            try
            {
                command->execute(model);
                st_1.push(command);
                while(!st_2.empty()) st_2.pop();
                model.clearErrorMessage();
            }
            catch (EditorException& e)
            {
               model.setErrorMessage(e.getReason());
            }
            view.refresh();
            // Note that you'll want to be more careful about when you delete
            // commands once you implement undo and redo.  For now, since
            // neither is implemented, I've just deleted it immediately
            // after executing it.  You'll need to wait to delete it until
            // you don't need it anymore.
        }
    }
}

(题图)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清欢_小铭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值