#include #include #include #include #include #include "buffer.h" #include "manager.h" #include "throw.h" using namespace std; Buffer::Buffer(Manager *manager) :manager(manager){} void Buffer::receive(const Command &cmd){ if(cmd[0]=="open_file"){ const string &fname=cmd[1]; filename=fname; ifstream file(fname); if(!file){ manager->receive({"error","Cannot open file '"+fname+"'"}); return; } 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++; } //TODO: optimise this renewLayout(screen[0].line,screen[0].part,lastWidth,lastHeight); } else { THROW("Unknown command"); } } static string showChar(char c){ if(c>=32&&c<127)return {c}; return {'\\','x', "0123456789abcdef"[(unsigned char)c/16], "0123456789abcdef"[(unsigned char)c%16]}; } /*static i64 charWidth(char c){ return showChar(c).size(); }*/ vector Buffer::layoutLine(const string &line,i64 linenum,i64 width){ assert(width>=4); vector layout; vector cur; i64 x=0; i64 linepart=0,fromx=0; for(i64 i=0;i<(i64)line.size();i++){ char c=line[i]; string repr=showChar(c); assert(repr.size()>0); if(x+(i64)repr.size()>=width){ layout.push_back({linenum,linepart,fromx,move(cur)}); cur.clear(); linepart++; fromx=i; x=0; } Cell cell={'\0',repr.size()!=1}; for(char rc : repr){ cell.c=rc; cur.push_back(cell); x++; } } if(cur.size()>0)layout.push_back({linenum,linepart,fromx,move(cur)}); return layout; } //Takes width without gutter void Buffer::performInitialLayout(i64 width,i64 height){ assert(width>0&&height>0); const i64 targetCursorScreenY=height/2; screen.clear(); if(tb.numLines()==0){ screen.push_back({0,0,0,{}}); return; } assert(cursor.line>=0&&cursor.x>=0&& cursor.linecursor.x){ cursorScreenY++; } //First, layout lines above the cursor line until the cursor is at or past halfway //the screen, or the buffer is exhausted. i64 topLine=cursor.line-1; //logical line while(topLine>=0&&cursorScreenY layout=layoutLine(tb[topLine],topLine,width); screen.insert(screen.begin(),layout.begin(),layout.end()); cursorScreenY+=layout.size(); topLine--; } //Remove any lines from the top until the cursor is exactly halfway the screen. //Store the removed lines in `spliced`. vector spliced; if(cursorScreenY>targetCursorScreenY){ for(i64 i=0;i layout=layoutLine(tb[bottomLine],bottomLine,width); screen.insert(screen.end(),layout.begin(),layout.end()); bottomLine++; } if((i64)screen.size()=0&&(i64)screen.size() layout=layoutLine(tb[topLine],topLine,width); screen.insert(screen.begin(),layout.begin(),layout.end()); topLine--; } if((i64)screen.size()>height){ //Oops, we overran a bit. Prune the end so that we fill the screen exactly. screen.resize(height); } } } } //Takes width without gutter void Buffer::renewLayout(i64 topLine,i64 topPart,i64 width,i64 height){ assert(width>0&&height>0); assert(topLine>=0&&topPart>=0); screen.clear(); if(tb.numLines()==0){ screen.push_back({0,0,0,{}}); return; } screen=layoutLine(tb.getLine(topLine),topLine,width); if(topPart>0)screen.erase(screen.begin(),screen.begin()+topPart); i64 bottomLine=topLine+1; while(bottomLine layout=layoutLine(tb[bottomLine],bottomLine,width); screen.insert(screen.begin(),layout.begin(),layout.end()); bottomLine++; } if((i64)screen.size()>height){ screen.resize(height); } } i64 numberWidth(i64 number){ if(number<0)return 1+numberWidth(-number); if(number==0)return 1; return (i64)log10(number)+1; } void Buffer::show(i64 atx,i64 aty,i64 width,i64 height){ static const Style gutterStyle={3,9,false,false}; static const Style textStyle={9,9,false,false}; static const Style specialStyle={5,9,false,false}; i64 gutterWidth=numberWidth(tb.numLines())+2; i64 newWidth=width-gutterWidth; if(newWidth!=lastWidth||height!=lastHeight){ if(lastWidth==-1)performInitialLayout(newWidth,height); else renewLayout(screen[0].line,screen[0].part,newWidth,height); lastWidth=newWidth; lastHeight=height; } pushcursor(); i64 y; for(y=0;y<(i64)screen.size();y++){ moveto(atx,aty+y); setstyle(&gutterStyle); i64 nspaces=gutterWidth-1-numberWidth(screen[y].line+1); for(i64 i=0;i