diff options
| -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;  | 
