diff options
author | tomsmeding <tom.smeding@gmail.com> | 2017-01-10 10:13:17 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2017-01-10 10:13:17 +0100 |
commit | 3e434c89de052c1909952746368e837fb68e0ae2 (patch) | |
tree | 9084824b4ae06233be9ddf3ae30cda4624666ba8 | |
parent | 121baddb4cd919d98bf5dfea0ad78ca0bee58a2e (diff) |
Move downward
-rw-r--r-- | buffer.cpp | 129 | ||||
-rw-r--r-- | buffer.h | 9 |
2 files changed, 101 insertions, 37 deletions
@@ -1,5 +1,6 @@ -#include <stdexcept> +#include <algorithm> #include <fstream> +#include <stdexcept> #include <cassert> #include <cmath> #include <cinttypes> @@ -15,8 +16,8 @@ using namespace std; Buffer::Buffer(Manager *manager) :manager(manager){} -void Buffer::receive(const Command &cmd){ - //TODO: optimise the renewLayout's in this function +void Buffer::handleCommand(const Command &cmd){ + //TODO: optimise the relayoutScreen's in this function if(cmd[0]=="open_file"){ const string &fname=cmd[1]; @@ -29,67 +30,100 @@ void Buffer::receive(const Command &cmd){ tb.read(file); } else if(cmd[0]=="insert_char"){ char c=cmd[1][0]; - if(c=='\n'){ - assert(false); - } else { - tb.insert(cursor.line,cursor.x,cmd[1][0]); - cursor.x++; - } - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + assert(c!='\n'); + tb.insert(cursor.line,cursor.x,cmd[1][0]); + cursor.x++; + relayoutScreen(); } else if(cmd[0]=="insert_newline"){ tb.insert(cursor.line,cursor.x,'\n'); cursor.x=0; cursor.line++; - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + relayoutScreen(); } else if(cmd[0]=="delete_backward"){ if(cursor.x==0&&cursor.line==0){ bel(); + return; + } + if(cursor.x>0){ + cursor.x--; + tb.erase(cursor.line,cursor.x); } else { - if(cursor.x>0){ - cursor.x--; - tb.erase(cursor.line,cursor.x); - } else { - cursor.line--; - cursor.x=tb.lineLen(cursor.line); - tb.erase(cursor.line,cursor.x); - } - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + cursor.line--; + cursor.x=tb.lineLen(cursor.line); + tb.erase(cursor.line,cursor.x); } + relayoutScreen(); } else if(cmd[0]=="delete_forward"){ if(cursor.line==tb.numLines()-1&&cursor.x==tb.lineLen(cursor.line)){ bel(); - } else { - tb.erase(cursor.line,cursor.x); - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + return; } + tb.erase(cursor.line,cursor.x); + relayoutScreen(); } else if(cmd[0]=="move_forward"){ if(cursor.line==tb.numLines()-1&&cursor.x==tb.lineLen(cursor.line)){ bel(); + return; + } + if(cursor.x==tb.lineLen(cursor.line)){ + cursor.x=0; + cursor.line++; } else { - if(cursor.x==tb.lineLen(cursor.line)){ - cursor.x=0; - cursor.line++; - } else { - cursor.x++; - } - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + cursor.x++; } } else if(cmd[0]=="move_backward"){ if(cursor.line==0&&cursor.x==0){ bel(); + return; + } + if(cursor.x==0){ + cursor.line--; + cursor.x=tb.lineLen(cursor.line); } else { - if(cursor.x==0){ - cursor.line--; - cursor.x=tb.lineLen(cursor.line); - } else { - cursor.x--; + cursor.x--; + } + } else if(cmd[0]=="move_downward"){ + Screenpos sp=findCursorInScreen(); + if(sp.x==-1){ + bel(); + return; + } + if(sp.y==(i64)screen.size()-1){ + if(screen[sp.y].line==tb.numLines()-1&& + (screen[sp.y].cells.size()==0 + ?tb.lineLen(screen[sp.y].line)==0 + :screen[sp.y].cells.back().linex==tb.lineLen(screen[sp.y].line)-1)){ + //so screen[sp.y] contains the end of that logical line + if(cursor.x==tb.lineLen(screen[sp.y].line)){ + bel(); + } else { + cursor.x=tb.lineLen(screen[sp.y].line); + } + return; } - renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); + screen.erase(screen.begin()); + relayoutScreen(); + } else { + sp.y++; + } + if(sp.y>=(i64)screen.size()){ + bel(); + return; + } + cursor.line=screen[sp.y].line; + if(sp.x>=(i64)screen[sp.y].cells.size()){ + cursor.x=tb.lineLen(cursor.line); + } else { + cursor.x=screen[sp.y].cells[sp.x].linex; } } else { THROW("Unknown command"); } - //cerr<<"New cursor is (line="<<cursor.line<<", x="<<cursor.x<<")"<<endl; +} + +void Buffer::receive(const Command &cmd){ + handleCommand(cmd); + cerr<<"New cursor is (line="<<cursor.line<<", x="<<cursor.x<<")"<<endl; } static string showChar(char c){ @@ -239,6 +273,27 @@ void Buffer::renewLayout(i64 topLine,i64 topPart,i64 width,i64 height){ } } +void Buffer::relayoutScreen(){ + renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); +} + +//Returns {-1,-1} if not found +Buffer::Screenpos Buffer::findCursorInScreen() const { + if(screen.size()==0)return {-1,-1}; + auto lineit=lower_bound(screen.begin(),screen.end(),cursor.line,[this](const ScreenLine &sl,i64 line){ + return sl.line<line||(sl.line==line&&sl.fromx<=cursor.x); + }); + if(lineit==screen.begin())return {-1,-1}; + --lineit; + const i64 y=distance(screen.begin(),lineit); + const vector<Cell> &cells=lineit->cells; + auto chrit=lower_bound(cells.begin(),cells.end(),cursor.x,[](const Cell &cell,i64 x){ + return cell.linex<x; + }); + const i64 x=distance(cells.begin(),chrit); + return {y,x}; +} + i64 numberWidth(i64 number){ if(number<0)return 1+numberWidth(-number); if(number==0)return 1; @@ -34,9 +34,18 @@ class Buffer{ }; Cursorpos cursor={0,0}; + struct Screenpos{ + i64 y,x; + }; + vector<ScreenLine> layoutLine(const string &line,i64 linenum,i64 width); void performInitialLayout(i64 width,i64 height); void renewLayout(i64 topLine,i64 topPart,i64 width,i64 height); + void relayoutScreen(); + + Screenpos findCursorInScreen() const; + + void handleCommand(const Command &cmd); public: string filename; |