211{
215 if(is_stdin_a_tty())
216 {
217 cursor = cursor_position();
218 screen = screen_size();
219 }
220
221 Model model;
222 model.prompt_string = prompt_string;
223
224
225
226 std::vector<std::string> history = m_history;
227 std::size_t history_pos = history.size();
228 history.push_back(
concat(model.lines));
229
232 render(scr, model, screen.columns());
233 std::cout << scr.render(1, cursor.
row(), term_attached) << std::flush;
234 bool not_complete = true;
235 while(not_complete)
236 {
239 if(key.isprint())
240 {
241 std::string before = model.lines[model.cursor_row - 1].substr(0, model.cursor_col - 1);
242 std::string newchar;
243 newchar.push_back(static_cast<char>(key));
244 std::string after = model.lines[model.cursor_row - 1].substr(model.cursor_col - 1);
245 model.lines[model.cursor_row - 1] = before += newchar += after;
246 model.cursor_col++;
247 }
248 else if(key == Key::Ctrl_D)
249 {
250 if(model.lines.size() == 1 && model.lines[model.cursor_row - 1].empty())
251 {
252 model.lines[model.cursor_row - 1].push_back(static_cast<char>(Key::Ctrl_D));
253 std::cout << "\n" << std::flush;
254 m_history.push_back(model.lines[0]);
255 return model.lines[0];
256 }
257 }
258 else
259 {
260 switch(key)
261 {
262 case Key::Enter:
263 not_complete = !iscomplete(
concat(model.lines));
265 else
266 break;
268 case Key::Backspace:
269 if(model.cursor_col > 1)
270 {
271 std::string before = model.lines[model.cursor_row - 1].substr(0, model.cursor_col - 2);
272 std::string after = model.lines[model.cursor_row - 1].substr(model.cursor_col - 1);
273 model.lines[model.cursor_row - 1] = before + after;
274 model.cursor_col--;
275 }
276 else if(model.cursor_col == 1 && model.cursor_row > 1)
277 {
278 model.cursor_col = model.lines[model.cursor_row - 2].size() + 1;
279 model.lines[model.cursor_row - 2] += model.lines[model.cursor_row - 1];
280 model.lines.erase(model.lines.begin() + static_cast<long>(model.cursor_row) - 1);
281 model.cursor_row--;
282 }
283 break;
284 case Key::Del:
285 if(model.cursor_col <= model.lines[model.cursor_row - 1].size())
286 {
287 std::string before = model.lines[model.cursor_row - 1].substr(0, model.cursor_col - 1);
288 std::string after = model.lines[model.cursor_row - 1].substr(model.cursor_col);
289 model.lines[model.cursor_row - 1] = before + after;
290 }
291 break;
292 case Key::ArrowLeft:
293 if(model.cursor_col > 1) { model.cursor_col--; }
294 break;
295 case Key::ArrowRight:
296 if(model.cursor_col <= model.lines[model.cursor_row - 1].size()) { model.cursor_col++; }
297 break;
298 case Key::Home: model.cursor_col = 1; break;
299 case Key::End: model.cursor_col = model.lines[model.cursor_row - 1].size() + 1; break;
300 case Key::ArrowUp:
301 if(model.cursor_row == 1)
302 {
303 if(history_pos > 0)
304 {
305 history[history_pos] =
concat(model.lines);
306 history_pos--;
307 model.lines =
split(history[history_pos]);
308 model.cursor_row = model.lines.size();
309 if(model.cursor_col > model.lines[model.cursor_row - 1].size() + 1) { model.cursor_col = model.lines[model.cursor_row - 1].size() + 1; }
310 if(model.lines.size() > scr.columns()) { scr.set_h(model.lines.size()); }
311 }
312 }
313 else
314 {
315 model.cursor_row--;
316 if(model.cursor_col > model.lines[model.cursor_row - 1].size() + 1) { model.cursor_col = model.lines[model.cursor_row - 1].size() + 1; }
317 }
318 break;
319 case Key::ArrowDown:
320 if(model.cursor_row == model.lines.size())
321 {
322 if(history_pos < history.size() - 1)
323 {
324 history[history_pos] =
concat(model.lines);
325 history_pos++;
326 model.lines =
split(history[history_pos]);
327 model.cursor_row = 1;
328 if(model.cursor_col > model.lines[model.cursor_row - 1].size() + 1) { model.cursor_col = model.lines[model.cursor_row - 1].size() + 1; }
329 if(model.lines.size() > scr.columns()) { scr.set_h(model.lines.size()); }
330 }
331 }
332 else
333 {
334 model.cursor_row++;
335 if(model.cursor_col > model.lines[model.cursor_row - 1].size() + 1) { model.cursor_col = model.lines[model.cursor_row - 1].size() + 1; }
336 }
337 break;
338 case Key::Ctrl_N:
339 {
340 std::string before = model.lines[model.cursor_row - 1].substr(0, model.cursor_col - 1);
341 std::string after = model.lines[model.cursor_row - 1].substr(model.cursor_col - 1);
342 model.lines[model.cursor_row - 1] = before;
343 if(model.cursor_row < model.lines.size())
344 {
345
346 model.lines.insert(model.lines.begin() + static_cast<long>(model.cursor_row), after);
347 }
348 else { model.lines.push_back(after); }
349 model.cursor_col = 1;
350 model.cursor_row++;
351 if(model.lines.size() > scr.columns()) { scr.set_h(model.lines.size()); }
352 break;
353 }
354 default: break;
355 }
356 }
357 render(scr, model, screen.columns());
358 std::cout << scr.render(1, cursor.
row(), term_attached) << std::flush;
359 if(cursor.
row() + scr.columns() - 1 > screen.rows())
360 {
361 cursor =
Cursor({Row(
static_cast<std::uint16_t
>(screen.rows() - (scr.columns() - 1))), Column(cursor.
column())});
362 std::cout << scr.render(1, cursor.
row(), term_attached) << std::flush;
363 }
364 }
365 std::string line_skips;
366 for(std::size_t i = 0; i <= model.lines.size() - model.cursor_row; i++) { line_skips += "\n"; }
367 std::cout << line_skips << std::flush;
368 m_history.push_back(
concat(model.lines));
369 return concat(model.lines);
370}
std::size_t column() const
Represents a rectangular window, as a 2D array of characters and their attributes.
#define CPP_TERMINAL_FALLTHROUGH
std::vector< std::string > split(const std::string &)
std::string concat(const std::vector< std::string > &)
void render(Term::Window &, const Model &, const std::size_t &)