#include "everything.hpp" // Save file from buffer void Editor::save() { std::ofstream outfile(filename); if(!outfile.good()) { std::cerr << "Bad filename"; return; } for(count_type i = 0; i < file.size(); ++i) outfile << file.get_line(i, 0) << std::endl; } // Clear line void Editor::clear_line(count_type i) { ::move(i, 0); clrtoeol(); } // Print any text void Editor::print_text(count_type i, string text) { clear_line(i); ::move(i, 0); adds(text); } // Print file content void Editor::print_file(count_type start) { auto lines = file.bulk_get_line(start, LINES); for(count_type i = 0; i < LINES; i++) if(i < lines.size()) print_text(i, lines[i]); else clear_line(i); } // Generic input taking template string Editor::get_input(string prompt, F func) { print_text(cur.r, prompt+": "); string s = ""; char ch = getch(); while((ch != ENTER && func(ch)) || ch == BS) { if(ch == BS) s.pop_back(); else s += ch; print_text(cur.r, prompt+": " + s); ch = getch(); } print_current_line(); return s; } // Taking user input - string string Editor::get_string(string prompt) { return get_input(prompt, [](char ch) { return true; }); } // Taking user input - number count_type Editor::get_number(string prompt) { return stoi(get_input(prompt, [](char ch) { return ch >= '0' && ch <= '9'; })); } // TODO undo // Jump to end of line void Editor::jump_line_end() { count_type line_size = file.get_line(file_offset+cur.r).size(); if(cur.c > line_size) cur.c = line_size; } // Cursor movement void Editor::move_cursor(char ch) { switch(ch) { case 'h': if(cur.c > 0) { cur.c -= 1; move(cur); } break; case 'j': if(file_offset + cur.r >= file.size()-1) break; if(cur.r < LINES-1) { cur.r += 1; move(cur); jump_line_end(); } else if(cur.r == LINES-1) { file_offset++; jump_line_end(); print_file(file_offset); } break; case 'k': if(cur.r > 0) { cur.r -= 1; move(cur); jump_line_end(); } else if(file_offset > 0) { file_offset--; jump_line_end(); print_file(file_offset); } break; case 'l': if(cur.c < file.get_line(file_offset+cur.r).size()) { cur.c += 1; move(cur); } break; } } // Jump to line void Editor::jump(count_type r) { if(r >= file.size()) r = file.size()-1; else if(r < 0) r = 0; if(r < file_offset) file_offset = r; else if(r >= file_offset + LINES) file_offset = r - LINES+1; cur.r = r - file_offset; jump_line_end(); move(cur); } // Find next string appearance std::pair Editor::find(string text) { count_type len = text.size(); count_type file_size = file.size(); for(count_type _r = 0; _r < file_size; ++_r) { count_type r = (file_offset + cur.r + _r) % file_size; count_type start = ((_r == 0) ? (cur.c+1) : 0); count_type pos = file.get_line(r, 0).find(text, start); if(pos != string::npos) return {true,{r, pos}}; } return {false, position()}; } bool Editor::take_action() { move(cur); char ch = getch(); switch(mode) { case NORMAL: print_current_line(); switch(ch) { case 'h': case 'j': case 'k': case 'l': move_cursor(ch); break; case 'g': jump(get_number("line number")); print_file(file_offset); break; case 'G': jump(file.size()); print_file(file_offset); break; case 'd': file.remove(file_offset + cur.r); if(file_offset + cur.r >= file.size()) jump(cur + file_offset); print_file(file_offset); break; case 'x': file.remove(cur + file_offset); print_current_line(); break; case 'o': file.insert(file_offset + cur.r, ""); jump_line_end(); print_file(file_offset); break; case 'q': return false; break; case 'w': save(); break; case 'i': mode = INSERT; break; case 'v': mode = SELECT; selection.pos = cur + file_offset; break; case 'f': last_find = get_string("to find"); case 'n': { auto result = find(last_find); if(!result.first) break; jump(result.second); } print_file(file_offset); break; case 's': last_find = get_string("to find"); last_replace = get_string("to replace"); case 'r': { auto result = find(last_find); if(!result.first) break; jump(result.second); replace(cur + file_offset, last_find.size(), last_replace); } print_file(file_offset); break; case 'p': selection.paste_selection(cur + file_offset); print_file(file_offset); break; default: break; } break; case INSERT: // TODO remake insert mode for better undo switch(ch) { case ESC: mode = NORMAL; // Change current row into current_insert TODO print_current_line(); break; case BS: // Modify current_insert TODO if(cur.c > 0) { cur.c -= 1; file.remove(cur + file_offset); } print_current_line(); break; case ENTER: // Modify current_insert and update TODO file.split_line(cur + file_offset); print_file(file_offset); cur.r++; jump_line_end(); break; case '\t': // Modify current_insert TODO file.insert(cur + file_offset, "\t"); cur.c += TAB_SIZE - (cur.c % TAB_SIZE); print_current_line(); break; default: // Modify current_insert TODO file.insert(cur + file_offset, string(1, ch)); cur.c += 1; print_current_line(); break; } break; case SELECT: print_current_line(); switch(ch) { case 'h': case 'j': case 'k': case 'l': move_cursor(ch); break; case 'g': jump(get_number("line number")); print_file(file_offset); break; case 'v': selection.copy_selection(cur + file_offset); mode = NORMAL; break; case 'x': selection.remove_selection(cur + file_offset); if(file_offset + cur.r >= file.size()) jump(cur + file_offset); print_file(file_offset); mode = NORMAL; break; default: mode = NORMAL; break; } break; } return true; }