summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2017-01-10 10:13:17 +0100
committertomsmeding <tom.smeding@gmail.com>2017-01-10 10:13:17 +0100
commit3e434c89de052c1909952746368e837fb68e0ae2 (patch)
tree9084824b4ae06233be9ddf3ae30cda4624666ba8
parent121baddb4cd919d98bf5dfea0ad78ca0bee58a2e (diff)
Move downward
-rw-r--r--buffer.cpp129
-rw-r--r--buffer.h9
2 files changed, 101 insertions, 37 deletions
diff --git a/buffer.cpp b/buffer.cpp
index 78f5e16..9b91e43 100644
--- a/buffer.cpp
+++ b/buffer.cpp
@@ -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;
diff --git a/buffer.h b/buffer.h
index fd9b062..4c15703 100644
--- a/buffer.h
+++ b/buffer.h
@@ -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;