/********************************************************************************* @file vim.c* @author 古么宁* @brief 文本编辑器,依赖 shell.h/shell.c******************************************************************************** COPYRIGHT(c) 2018 GoodMorning********************************************************************************//* Includes ---------------------------------------------------*/#include <string.h>#include <stdint.h> //定义了很多数据类型#include "shell.h"#include "vim.h"/* Private types ------------------------------------------------------------*/enum VIM_STATE{VIM_READ_ONLY = 0,VIM_EDITING ,VIM_COMMAND ,VIM_QIUT};struct vim_edit_buf{vim_fputs_t fputs; //文件输出char * fpath; //命令行输入的编辑文件名char * edit; //当前编辑位置uint16_t rowmax;//文件共有几行uint16_t rows; //文件光标所在行位置uint16_t cols; //文件光标所在列位置uint16_t tail; //文件尾部位置char editbuf[VIM_MAX_EDIT]; //文件编辑内存char printbuf[VIM_MAX_EDIT];//文件打印中转内存char option;char state;};/* Private macro ------------------------------------------------------------*///#define VIM_USE_HEAP //开关宏,是否使用堆内存,屏蔽掉则使用静态内存#ifdef VIM_USE_HEAP //如果使用堆内存,需要提供 VIM_MALLOC 和 VIM_FREE#include "heaplib.h"#define VIM_MALLOC(bytes) sys_malloc(bytes)#define VIM_FREE(buf) sys_free(buf)#else //使用静态变量的情况static struct vim_edit_buf vimsbuf = {0};#define VIM_MALLOC(bytes) ((vimsbuf.fputs == NULL)?((void*)(&vimsbuf)):NULL)#define VIM_FREE(buf) (((struct vim_edit_buf*)(buf))->fputs = NULL)#endif/* Private variables ------------------------------------------------------------*/static const char clearline[] = "33円[2K\r\n";static const char waiting_title[] = "'i'(Edit) or ':'(quit/save)";static const char editing_title[] = "Editing...press ESC to quit";/* Private function prototypes -----------------------------------------------*//* Gorgeous Split-line -----------------------------------------------*//*** @brief cursor_up* 编辑器响应上箭头* @param vim 编辑内存* @return void*/static void cursor_up(struct vim_edit_buf * vimedit){if (vimedit->rows > 1) { //如果编辑所在位置为第一行,则不进行响应char * ptr = vimedit->edit; //当前编辑位置uint32_t cnt;if ((--vimedit->rows) > 1) {for ( ; * ptr != '\n' ; --ptr ); //回到上一行结尾处的'\n'for ( ; *(ptr-1) != '\n' ; --ptr ); //上一行开头}else {//如果现在是第二行,则回到第一行所在位置ptr = vimedit->editbuf;}for (cnt = 1;cnt < vimedit->cols ;++cnt) { //计算当前行的列位置if (*ptr == '\r' || *ptr == '\n') //当前行比下一行短,则没有办法回到下一行所在的列位置break;else++ptr;}vimedit->cols = cnt;vimedit->edit = ptr; //更新当前编辑位置printk("033円[%d;%dH",vimedit->rows + 1,vimedit->cols); //打印光标位置}}/*** @brief cursor_down* 编辑器响应下箭头* @param vim 编辑内存* @return void*/static void cursor_down(struct vim_edit_buf * vimedit){if (vimedit->rows < vimedit->rowmax){ //如果当前行不是文本最后一行,响应下箭头char * ptr = vimedit->edit;uint32_t cnt;while( *ptr++ != '\n' );//下一行开头处for (cnt = 1; cnt < vimedit->cols ; ++cnt) {if ( *ptr == '\r' || *ptr == '0円' || *ptr == '\n')//比上一行短时,无法移动光标至原来的列位置break;else++ptr;}printl(vimedit->edit,ptr - vimedit->edit);++vimedit->rows; //更新行数vimedit->cols = cnt;//更行列数vimedit->edit = ptr;//更新当前编辑位置}}/*** @brief cursor_right* 编辑器响应右箭头* @param vim 编辑内存* @return void*/static void cursor_right(struct vim_edit_buf * vimedit){char * edit = vimedit->edit;if (*edit == '\r' || *edit == '0円' || *edit == '\n')//行末尾return ;++vimedit->cols;++vimedit->edit;printl(edit,1);}/*** @brief cursor_left* 编辑器响应左箭头* @param vim 编辑内存* @return void*/static void cursor_left(struct vim_edit_buf * vimedit){if (vimedit->edit == vimedit->editbuf || vimedit->cols < 2)//行开头return;--vimedit->edit;--vimedit->cols;printl("\b",1);}/*** @brief cursor_move* 编辑器响应箭头* @param vim 编辑内存* @return void*/static int cursor_move(struct vim_edit_buf * vimedit , char arrow){switch( arrow ) {case 'A':cursor_up(vimedit);break; //上箭头case 'B':cursor_down(vimedit);break;//下箭头case 'C':cursor_right(vimedit);break;//右箭头case 'D':cursor_left(vimedit);break;//左箭头default : return -1;}return 0;}/*** @brief vim_backspace* 编辑器回删一个字符* @param vim 编辑内存* @return void*/static void vim_backspace(struct vim_edit_buf * vim){char * print = vim->printbuf;char * edit = vim->edit; //当前编辑位置char * tail = &vim->editbuf[vim->tail];//原编辑区结尾;//if (*(vim->edit-1) != '\n') //如果当前编辑位置不是行开头if (vim->cols != 1) { //如果当前编辑位置不是行开头char * copy = vim->edit;//找到当前行结束位置,并复制到打印内存中for (*print++ = '\b' ; *copy != '\r' && *copy && *copy != '\n' ; *print++ = *copy++);*print++ = ' '; //覆盖当前行最后一个字符显示*print++ = '\b'; //光标回显//计算光标回退个数for (uint32_t cnt = copy - vim->edit ; cnt-- ;*print++ = '\b' );//如 abUcd 中删除U,需要左移cd,并打印两个 '\b' 使光标回到 ab 处for (copy = edit - 1 ; edit < tail ; *copy++ = *edit++);--vim->cols;--vim->edit;--vim->tail;vim->editbuf[vim->tail] = 0;//末端添加字符串结束符printl(vim->printbuf,print - vim->printbuf);}else {//当前编辑位置是行开头,回退一行char * prevlines ; //当前编辑点上一行的开头char * prevlinee ; //当前编辑点上一行的结尾if (vim->rows > 2) //当前编辑行不是第二行for (prevlines = edit-1 ; *(prevlines-1) != '\n' ; --prevlines);//回到上一行开头elseprevlines = vim->editbuf; //回到第一行开头//找到上一行结尾处,已知有下一行,不需要判断 0円for (prevlinee = prevlines ; *prevlinee != '\r' && *prevlinee != '\n' ; ++prevlinee);//控制台清空编辑点所在行以及后面所有的内容显示for(uint32_t i = vim->rows ; i <= vim->rowmax ; ++i )printl((char*)clearline , sizeof(clearline)-1);//把当前编辑点内容考到上一行结尾//memcpy(prevlinee, edit ,tail - edit);for (char * copy = prevlinee ; edit < tail ; *copy++ = *edit++);vim->rowmax -= 1;vim->rows -= 1;vim->tail -= (vim->edit - prevlinee);//更新编辑尾部,适应 '\r\n'vim->edit = prevlinee ; //更新当前编辑位置为上一行结尾vim->cols = prevlinee-prevlines+1; //更新当前列位置为上一行结尾vim->editbuf[vim->tail] = 0; //末端添加字符串结束符printk("033円[%d;%dH",vim->rows+1,vim->cols);//光标回到编辑点位置printl(vim->edit,strlen(vim->edit)); //打印剩余内容printk("033円[%d;%dH",vim->rows+1,vim->cols);//光标再次回到编辑点位置}}/*** @brief vim_insert_char* 编辑器插入一个普通字符* @param vim 编辑内存* @param ascii 所插入字符* @return void*/static void vim_insert_char(struct vim_edit_buf * vim,char ascii){char * print = vim->printbuf ;char * tail = &vim->editbuf[vim->tail];//tail 所处位置是字符串结束符的位置char * copy = vim->edit;//计算需要打印的字符串,找到当前行结束位置for (*print++ = ascii; *copy != '\r' && *copy != '\n' && *copy ; *print++ = *copy++);//计算当前行需要回退的光标数for (uint32_t cnt = copy - vim->edit ; cnt-- ; *print++ = '\b');//如 abcd 中在bc插入U,需要右移cd,并打印两个 '\b' 使光标回到 abU 处for (copy = tail - 1; copy >= vim->edit ; *tail-- = *copy--);*vim->edit = ascii; //插入字符++vim->edit;++vim->cols;++vim->tail;vim->editbuf[vim->tail] = 0; //末端添加字符串结束符printl(vim->printbuf,print - vim->printbuf);}/*** @brief vim_insert_newline* 编辑器插入换行符/回车符* @param vim 编辑内存* @param ascii 所插入字符* @return void*/static void vim_insert_newline(struct vim_edit_buf * vim){char * tail = &vim->editbuf[vim->tail];//tail 所处位置是字符串结束符的位置char * copy ;//清空此行以及后面所有内容for(uint32_t i = vim->rows ; i <= vim->rowmax ; ++i )printl((char*)clearline,sizeof(clearline)-1);printk("033円[%d;%dH",vim->rows+1,1);//光标回到当前编辑行开头if (vim->rows > 1)for (copy=vim->edit ; *(copy-1) != '\n' ; --copy);elsecopy = vim->editbuf;printl(copy,vim->edit-copy); //打印至当前编辑位置tail += 1;//新的尾部// 当前编辑位置后移两个字节空间for (copy = tail-2 ; copy >= vim->edit ; *tail-- = *copy--) ;*vim->edit++ = '\r';*vim->edit++ = '\n';vim->tail += 2;vim->rows += 1;vim->cols = 1;vim->rowmax += 1;vim->editbuf[vim->tail] = 0; //末端添加字符串结束符tail = &vim->editbuf[vim->tail] - 1;copy = (vim->edit - 2);printl(copy,tail-copy); //打印至当前编辑位置printk("033円[%d;%dH",vim->rows+1,1);}/*** @brief vim_insert_newline* 编辑过程接收字符* @param vim 编辑内存* @param data 所接收字符* @return void*/static void vim_edit_getchar(struct vim_edit_buf * vim,char data){if (KEYCODE_CTRL_C == data || KEYCODE_TAB == data ||KEYCODE_END == data || KEYCODE_HOME == data ) { //一些特别的字符过滤return ;}if (KEYCODE_BACKSPACE == data || 0x7f == data) {//0x7f ,for puttyif (vim->editbuf != vim->edit)vim_backspace(vim);}elseif (vim->tail < VIM_MAX_EDIT/2) {//插入字符if ('\r' == data || '\n' == data ) //插入换行符vim_insert_newline(vim);elsevim_insert_char(vim , data); //插入普通字符}}/*** @brief vim_edit* 键盘数据流入* @param vim 编辑内存* @return void*/static void shell_vim_gets(struct shell_input * shell ,char * buf , int len){struct vim_edit_buf * vimedit = (struct vim_edit_buf *)shell->apparg ;for ( ; len ; --len , ++buf)switch(vimedit->state) { //状态机case VIM_READ_ONLY: //文本只读过程if (*buf == 'i') { //键盘输入 'i'vimedit->state = VIM_EDITING;//进入编辑模式printk("033円[%d;%dH033円[2K\r\t",1,1);//光标回到第一行并清空第一行printl((char*)editing_title,sizeof(editing_title)-1); //打印提示信息printk("033円[%d;%dH",vimedit->rows + 1,vimedit->cols);//恢复光标位置}elseif (*buf == ':') {vimedit->option = 0;vimedit->state = VIM_COMMAND;printk("033円[%d;%dH033円[2K\r(w/q):",1,1);//光标回到第一行并清空第一行}elseif ( buf[0] == '033円' && len > 1 && buf[1] == '[' ) {cursor_move(vimedit,buf[2]);}break;case VIM_EDITING: //文本编辑过程if (*buf == '033円') {if ( len > 2 && buf[1] == '[' ) {if (0 == cursor_move(vimedit,buf[2])){//如果是箭头输入len -= 2;buf += 2;}elsevim_edit_getchar(vimedit ,* buf);}else {vimedit->state = VIM_READ_ONLY; //如果是单按键 Esc ,回到只读模式printk("033円[%d;%dH033円[2K\r",1,1);//光标回到第一行并清空第一行printk("\t%s",waiting_title); //打印提示信息printk("033円[%d;%dH",vimedit->rows + 1,vimedit->cols);//恢复光标位置}}else {vim_edit_getchar(vimedit ,* buf);}break;case VIM_COMMAND: //等待命令if (*buf == 'q' ||*buf == 'w') {vimedit->state = VIM_QIUT;vimedit->option = *buf;printl(buf,1);}elseif (*buf == '033円' ) { //&& len == 1)vimedit->state = VIM_READ_ONLY; //进入只读模式vimedit->edit = vimedit->editbuf;vimedit->cols = 1;vimedit->rows = 1;printk("033円[2K\r\t%s\r\n",waiting_title);//打印提示信息}break;case VIM_QIUT: //等待退出if (*buf == KEYCODE_BACKSPACE || *buf == 0x7f) { //回退键vimedit->state = VIM_COMMAND;printl("\b\b",3);}elseif (*buf == '\r' || *buf == '\n') { //回车确认if ('w' == vimedit->option)//输入保存,则输出此文件vimedit->fputs(vimedit->fpath,vimedit->editbuf,vimedit->tail);VIM_FREE(vimedit);shell->apparg = NULL;shell->gets = cmdline_gets;printk("033円[2J033円[%d;%dH%s",1,1,shell->sign);}elseif (*buf == '033円' ) { //&& len == 1)vimedit->state = VIM_READ_ONLY; //进入只读模式vimedit->edit = vimedit->editbuf;vimedit->cols = 1;vimedit->rows = 1;printk("033円[2K\r\t%s\r\n",waiting_title);//打印提示信息}break;default:;}}/*** @brief shell_into_edit* 当前输入进入文本编辑模式* @param shell 需要进行文本编辑的 shell 交互* @param fgets 获取编辑文本数据源的接口* @param fputs 更新文本数据源的接口* @return void*/void shell_into_edit(struct shell_input * shell,vim_fgets_t fgets ,vim_fputs_t fputs){char * argv[2] = {NULL};struct vim_edit_buf * edit;shell->apparg = VIM_MALLOC(sizeof(struct vim_edit_buf));if ( NULL == shell->apparg ) {printk("not enough memery\r\n");return ;}cmdline_strtok(shell->cmdline,argv,2);//提取路径信息,路径名称为第二个参数edit = (struct vim_edit_buf *)(shell->apparg);edit->fpath = argv[1]; //路径名称为第二个参数//尝试打开,如果失败则返回if (VIM_FILE_OK != fgets(edit->fpath,&edit->editbuf[0],&edit->tail)) {VIM_FREE(shell->apparg);return ;}shell->gets = shell_vim_gets; //重定义数据流输入,编辑文件模式if (default_puts == shell->puts)default_puts = NULL;edit->fputs = fputs;edit->editbuf[edit->tail] = 0;edit->edit = edit->editbuf;edit->state = VIM_READ_ONLY;edit->option = 0;edit->cols = 1;edit->rows = 1;edit->rowmax = 1;//扫描文件共有几行for (char * editbuf = edit->editbuf ; *editbuf ; ++editbuf) {if (*editbuf == '\n')++edit->rowmax;}//清空屏幕,并打印文本内容printk("033円[2J033円[%d;%dH",1,1);printk("\t%s\r\n%s",waiting_title,edit->editbuf);printk("033円[%d;%dH",2,1);}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。