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