Skip to content

Commit b3b8eb4

Browse files
authored
Merge pull request #49 from martinRenou/prompt_api
Add prompt to the library API
2 parents 4c6dfe3 + 273e535 commit b3b8eb4

File tree

2 files changed

+115
-111
lines changed

2 files changed

+115
-111
lines changed

cpp-terminal/terminal.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,120 @@ class Window
715715
}
716716
};
717717

718+
// This model contains all the information about the state of the prompt in an
719+
// abstract way, irrespective of where or how it is rendered.
720+
struct Model
721+
{
722+
std::string prompt_string; // The string to show as the prompt
723+
std::string input; // The current input string in the prompt
724+
// The current cursor position in the "input" string, starting from (1,1)
725+
size_t cursor_col, cursor_row;
726+
};
727+
728+
inline std::string render(const Model &m, int prompt_row, int term_cols)
729+
{
730+
std::string out;
731+
out = cursor_off();
732+
out += move_cursor(prompt_row, 1) + m.prompt_string + m.input;
733+
size_t last_col = m.prompt_string.size() + m.input.size();
734+
for (size_t i=0; i < term_cols-last_col; i++) {
735+
out.append(" ");
736+
}
737+
out.append(move_cursor(prompt_row+m.cursor_row-1,
738+
m.prompt_string.size() + m.cursor_col));
739+
out.append(cursor_on());
740+
return out;
741+
}
742+
743+
static std::vector<std::string> PROMPT_HISTORY;
744+
745+
// Create a prompt in a given terminal.
746+
inline std::string prompt(const Terminal &term, const std::string &prompt_string,
747+
std::vector<std::string> &history = PROMPT_HISTORY)
748+
{
749+
int row, col;
750+
term.get_cursor_position(row, col);
751+
int rows, cols;
752+
term.get_term_size(rows, cols);
753+
754+
Model m;
755+
m.prompt_string = prompt_string;
756+
m.cursor_col = 1;
757+
m.cursor_row = 1;
758+
759+
// Make a local copy of history that can be modified by the user. All
760+
// changes will be forgotten once a command is submitted.
761+
std::vector<std::string> hist = history;
762+
size_t history_pos = hist.size();
763+
hist.push_back(m.input); // Push back empty input
764+
765+
int key;
766+
std::cout << render(m, row, cols) << std::flush;
767+
while ((key = term.read_key()) != Key::ENTER) {
768+
if ( (key >= 'a' && key <= 'z') ||
769+
(key >= 'A' && key <= 'Z') ||
770+
(!iscntrl(key) && key < 128) ) {
771+
std::string before = m.input.substr(0, m.cursor_col-1);
772+
std::string newchar; newchar.push_back(key);
773+
std::string after = m.input.substr(m.cursor_col-1);
774+
m.input = before + newchar + after;
775+
m.cursor_col++;
776+
} else if (key == CTRL_KEY('d')) {
777+
if (m.input.size() == 0) {
778+
m.input.push_back(CTRL_KEY('d'));
779+
break;
780+
}
781+
} else {
782+
switch (key) {
783+
case Key::BACKSPACE:
784+
if (m.cursor_col > 1) {
785+
std::string before = m.input.substr(0, m.cursor_col-2);
786+
std::string after = m.input.substr(m.cursor_col-1);
787+
m.input = before + after;
788+
m.cursor_col--;
789+
}
790+
break;
791+
case Key::ARROW_LEFT:
792+
if (m.cursor_col > 1) {
793+
m.cursor_col--;
794+
}
795+
break;
796+
case Key::ARROW_RIGHT:
797+
if (m.cursor_col <= m.input.size()) {
798+
m.cursor_col++;
799+
}
800+
break;
801+
case Key::HOME:
802+
m.cursor_col = 1;
803+
break;
804+
case Key::END:
805+
m.cursor_col = m.input.size()+1;
806+
break;
807+
case Key::ARROW_UP:
808+
if (history_pos > 0) {
809+
hist[history_pos] = m.input;
810+
history_pos--;
811+
m.input = hist[history_pos];
812+
m.cursor_col = m.input.size()+1;
813+
}
814+
break;
815+
case Key::ARROW_DOWN:
816+
if (history_pos < hist.size()-1) {
817+
hist[history_pos] = m.input;
818+
history_pos++;
819+
m.input = hist[history_pos];
820+
m.cursor_col = m.input.size()+1;
821+
}
822+
break;
823+
}
824+
}
825+
std::cout << render(m, row, cols) << std::flush;
826+
}
827+
std::cout << "\n" << std::flush;
828+
history.push_back(m.input);
829+
return m.input;
830+
}
831+
718832
} // namespace Term
719833

720834
#endif // TERMINAL_H

examples/prompt.cpp

Lines changed: 1 addition & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -3,118 +3,8 @@
33
#include <vector>
44

55
using Term::Terminal;
6-
using Term::Key;
7-
using Term::move_cursor;
8-
using Term::cursor_off;
9-
using Term::cursor_on;
6+
using Term::prompt;
107

11-
// This model contains all the information about the state of the prompt in an
12-
// abstract way, irrespective of where or how it is rendered.
13-
struct Model {
14-
std::string prompt_string; // The string to show as the prompt
15-
std::string input; // The current input string in the prompt
16-
// The current cursor position in the "input" string, starting from (1,1)
17-
size_t cursor_col, cursor_row;
18-
};
19-
20-
std::string render(const Model &m, int prompt_row, int term_cols) {
21-
std::string out;
22-
out = cursor_off();
23-
out += move_cursor(prompt_row, 1) + m.prompt_string + m.input;
24-
size_t last_col = m.prompt_string.size() + m.input.size();
25-
for (size_t i=0; i < term_cols-last_col; i++) {
26-
out.append(" ");
27-
}
28-
out.append(move_cursor(prompt_row+m.cursor_row-1,
29-
m.prompt_string.size() + m.cursor_col));
30-
out.append(cursor_on());
31-
return out;
32-
}
33-
34-
std::string prompt(const Terminal &term, const std::string &prompt_string,
35-
std::vector<std::string> &history) {
36-
int row, col;
37-
term.get_cursor_position(row, col);
38-
int rows, cols;
39-
term.get_term_size(rows, cols);
40-
41-
Model m;
42-
m.prompt_string = prompt_string;
43-
m.cursor_col = 1;
44-
m.cursor_row = 1;
45-
46-
// Make a local copy of history that can be modified by the user. All
47-
// changes will be forgotten once a command is submitted.
48-
std::vector<std::string> hist = history;
49-
size_t history_pos = hist.size();
50-
hist.push_back(m.input); // Push back empty input
51-
52-
int key;
53-
std::cout << render(m, row, cols) << std::flush;
54-
while ((key = term.read_key()) != Key::ENTER) {
55-
if ( (key >= 'a' && key <= 'z') ||
56-
(key >= 'A' && key <= 'Z') ||
57-
(!iscntrl(key) && key < 128) ) {
58-
std::string before = m.input.substr(0, m.cursor_col-1);
59-
std::string newchar; newchar.push_back(key);
60-
std::string after = m.input.substr(m.cursor_col-1);
61-
m.input = before + newchar + after;
62-
m.cursor_col++;
63-
} else if (key == CTRL_KEY('d')) {
64-
if (m.input.size() == 0) {
65-
m.input.push_back(CTRL_KEY('d'));
66-
break;
67-
}
68-
} else {
69-
switch (key) {
70-
case Key::BACKSPACE:
71-
if (m.cursor_col > 1) {
72-
std::string before = m.input.substr(0, m.cursor_col-2);
73-
std::string after = m.input.substr(m.cursor_col-1);
74-
m.input = before + after;
75-
m.cursor_col--;
76-
}
77-
break;
78-
case Key::ARROW_LEFT:
79-
if (m.cursor_col > 1) {
80-
m.cursor_col--;
81-
}
82-
break;
83-
case Key::ARROW_RIGHT:
84-
if (m.cursor_col <= m.input.size()) {
85-
m.cursor_col++;
86-
}
87-
break;
88-
case Key::HOME:
89-
m.cursor_col = 1;
90-
break;
91-
case Key::END:
92-
m.cursor_col = m.input.size()+1;
93-
break;
94-
case Key::ARROW_UP:
95-
if (history_pos > 0) {
96-
hist[history_pos] = m.input;
97-
history_pos--;
98-
m.input = hist[history_pos];
99-
m.cursor_col = m.input.size()+1;
100-
}
101-
break;
102-
case Key::ARROW_DOWN:
103-
if (history_pos < hist.size()-1) {
104-
hist[history_pos] = m.input;
105-
history_pos++;
106-
m.input = hist[history_pos];
107-
m.cursor_col = m.input.size()+1;
108-
}
109-
break;
110-
}
111-
}
112-
std::cout << render(m, row, cols) << std::flush;
113-
}
114-
std::cout << "\n" << std::flush;
115-
history.push_back(m.input);
116-
return m.input;
117-
}
1188

1199
int main() {
12010
try {

0 commit comments

Comments
 (0)