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