1 #include <regex>
2 #include <string>
3 #include <vector>
4 #include <cerrno>
5 #include <cctype>
6 #include <cstdlib>
7 #include <utility>
8 #include <iomanip>
9 #include <iostream>
10 #include <thread>
11 #include <chrono>
12 
13 #include "replxx.hxx"
14 #include "util.h"
15 
16 using Replxx = replxx::Replxx;
17 
18 class Tick {
19 	typedef std::vector<char32_t> keys_t;
20 	std::thread _thread;
21 	int _tick;
22 	bool _alive;
23 	keys_t _keys;
24 	Replxx& _replxx;
25 public:
Tick(Replxx & replxx_,std::string const & keys_={} )26 	Tick( Replxx& replxx_, std::string const& keys_ = {} )
27 		: _thread()
28 		, _tick( 0 )
29 		, _alive( false )
30 		, _keys( keys_.begin(), keys_.end() )
31 		, _replxx( replxx_ ) {
32 	}
start()33 	void start() {
34 		_alive = true;
35 		_thread = std::thread( &Tick::run, this );
36 	}
stop()37 	void stop() {
38 		_alive = false;
39 		_thread.join();
40 	}
run()41 	void run() {
42 		std::string s;
43 		while ( _alive ) {
44 			if ( _keys.empty() ) {
45 				_replxx.print( "%d\n", _tick );
46 			} else if ( _tick < static_cast<int>( _keys.size() ) ) {
47 				_replxx.emulate_key_press( _keys[_tick] );
48 			} else {
49 				break;
50 			}
51 			++ _tick;
52 			std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
53 		}
54 	}
55 };
56 
57 // prototypes
58 Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& user_data);
59 Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& user_data);
60 void hook_color(std::string const& str, Replxx::colors_t& colors, std::vector<std::pair<std::string, Replxx::Color>> const& user_data);
61 
hook_completion(std::string const & context,int & contextLen,std::vector<std::string> const & examples)62 Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& examples) {
63 	Replxx::completions_t completions;
64 	int utf8ContextLen( context_len( context.c_str() ) );
65 	int prefixLen( context.length() - utf8ContextLen );
66 	if ( ( prefixLen > 0 ) && ( context[prefixLen - 1] == '\\' ) ) {
67 		-- prefixLen;
68 		++ utf8ContextLen;
69 	}
70 	contextLen = utf8str_codepoint_len( context.c_str() + prefixLen, utf8ContextLen );
71 
72 	std::string prefix { context.substr(prefixLen) };
73 	if ( prefix == "\\pi" ) {
74 		completions.push_back( "π" );
75 	} else {
76 		for (auto const& e : examples) {
77 			if (e.compare(0, prefix.size(), prefix) == 0) {
78 				Replxx::Color c( Replxx::Color::DEFAULT );
79 				if ( e.find( "brightred" ) != std::string::npos ) {
80 					c = Replxx::Color::BRIGHTRED;
81 				} else if ( e.find( "red" ) != std::string::npos ) {
82 					c = Replxx::Color::RED;
83 				}
84 				completions.emplace_back(e.c_str(), c);
85 			}
86 		}
87 	}
88 
89 	return completions;
90 }
91 
hook_hint(std::string const & context,int & contextLen,Replxx::Color & color,std::vector<std::string> const & examples)92 Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& examples) {
93 	Replxx::hints_t hints;
94 
95 	// only show hint if prefix is at least 'n' chars long
96 	// or if prefix begins with a specific character
97 
98 	int utf8ContextLen( context_len( context.c_str() ) );
99 	int prefixLen( context.length() - utf8ContextLen );
100 	contextLen = utf8str_codepoint_len( context.c_str() + prefixLen, utf8ContextLen );
101 	std::string prefix { context.substr(prefixLen) };
102 
103 	if (prefix.size() >= 2 || (! prefix.empty() && prefix.at(0) == '.')) {
104 		for (auto const& e : examples) {
105 			if (e.compare(0, prefix.size(), prefix) == 0) {
106 				hints.emplace_back(e.c_str());
107 			}
108 		}
109 	}
110 
111 	// set hint color to green if single match found
112 	if (hints.size() == 1) {
113 		color = Replxx::Color::GREEN;
114 	}
115 
116 	return hints;
117 }
118 
hook_color(std::string const & context,Replxx::colors_t & colors,std::vector<std::pair<std::string,Replxx::Color>> const & regex_color)119 void hook_color(std::string const& context, Replxx::colors_t& colors, std::vector<std::pair<std::string, Replxx::Color>> const& regex_color) {
120 	// highlight matching regex sequences
121 	for (auto const& e : regex_color) {
122 		size_t pos {0};
123 		std::string str = context;
124 		std::smatch match;
125 
126 		while(std::regex_search(str, match, std::regex(e.first))) {
127 			std::string c{ match[0] };
128 			std::string prefix( match.prefix().str() );
129 			pos += utf8str_codepoint_len( prefix.c_str(), static_cast<int>( prefix.length() ) );
130 			int len( utf8str_codepoint_len( c.c_str(), static_cast<int>( c.length() ) ) );
131 
132 			for (int i = 0; i < len; ++i) {
133 				colors.at(pos + i) = e.second;
134 			}
135 
136 			pos += len;
137 			str = match.suffix();
138 		}
139 	}
140 }
141 
message(Replxx & replxx,std::string s,char32_t)142 Replxx::ACTION_RESULT message( Replxx& replxx, std::string s, char32_t ) {
143 	replxx.invoke( Replxx::ACTION::CLEAR_SELF, 0 );
144 	replxx.print( "%s\n", s.c_str() );
145 	replxx.invoke( Replxx::ACTION::REPAINT, 0 );
146 	return ( Replxx::ACTION_RESULT::CONTINUE );
147 }
148 
main(int argc_,char ** argv_)149 int main( int argc_, char** argv_ ) {
150 	// words to be completed
151 	std::vector<std::string> examples {
152 		".help", ".history", ".quit", ".exit", ".clear", ".prompt ",
153 		"hello", "world", "db", "data", "drive", "print", "put",
154 		"color_black", "color_red", "color_green", "color_brown", "color_blue",
155 		"color_magenta", "color_cyan", "color_lightgray", "color_gray",
156 		"color_brightred", "color_brightgreen", "color_yellow", "color_brightblue",
157 		"color_brightmagenta", "color_brightcyan", "color_white", "color_normal",
158 	};
159 
160 	// highlight specific words
161 	// a regex string, and a color
162 	// the order matters, the last match will take precedence
163 	using cl = Replxx::Color;
164 	std::vector<std::pair<std::string, cl>> regex_color {
165 		// single chars
166 		{"\\`", cl::BRIGHTCYAN},
167 		{"\\'", cl::BRIGHTBLUE},
168 		{"\\\"", cl::BRIGHTBLUE},
169 		{"\\-", cl::BRIGHTBLUE},
170 		{"\\+", cl::BRIGHTBLUE},
171 		{"\\=", cl::BRIGHTBLUE},
172 		{"\\/", cl::BRIGHTBLUE},
173 		{"\\*", cl::BRIGHTBLUE},
174 		{"\\^", cl::BRIGHTBLUE},
175 		{"\\.", cl::BRIGHTMAGENTA},
176 		{"\\(", cl::BRIGHTMAGENTA},
177 		{"\\)", cl::BRIGHTMAGENTA},
178 		{"\\[", cl::BRIGHTMAGENTA},
179 		{"\\]", cl::BRIGHTMAGENTA},
180 		{"\\{", cl::BRIGHTMAGENTA},
181 		{"\\}", cl::BRIGHTMAGENTA},
182 
183 		// color keywords
184 		{"color_black", cl::BLACK},
185 		{"color_red", cl::RED},
186 		{"color_green", cl::GREEN},
187 		{"color_brown", cl::BROWN},
188 		{"color_blue", cl::BLUE},
189 		{"color_magenta", cl::MAGENTA},
190 		{"color_cyan", cl::CYAN},
191 		{"color_lightgray", cl::LIGHTGRAY},
192 		{"color_gray", cl::GRAY},
193 		{"color_brightred", cl::BRIGHTRED},
194 		{"color_brightgreen", cl::BRIGHTGREEN},
195 		{"color_yellow", cl::YELLOW},
196 		{"color_brightblue", cl::BRIGHTBLUE},
197 		{"color_brightmagenta", cl::BRIGHTMAGENTA},
198 		{"color_brightcyan", cl::BRIGHTCYAN},
199 		{"color_white", cl::WHITE},
200 		{"color_normal", cl::NORMAL},
201 
202 		// commands
203 		{"\\.help", cl::BRIGHTMAGENTA},
204 		{"\\.history", cl::BRIGHTMAGENTA},
205 		{"\\.quit", cl::BRIGHTMAGENTA},
206 		{"\\.exit", cl::BRIGHTMAGENTA},
207 		{"\\.clear", cl::BRIGHTMAGENTA},
208 		{"\\.prompt", cl::BRIGHTMAGENTA},
209 
210 		// numbers
211 		{"[\\-|+]{0,1}[0-9]+", cl::YELLOW}, // integers
212 		{"[\\-|+]{0,1}[0-9]*\\.[0-9]+", cl::YELLOW}, // decimals
213 		{"[\\-|+]{0,1}[0-9]+e[\\-|+]{0,1}[0-9]+", cl::YELLOW}, // scientific notation
214 
215 		// strings
216 		{"\".*?\"", cl::BRIGHTGREEN}, // double quotes
217 		{"\'.*?\'", cl::BRIGHTGREEN}, // single quotes
218 	};
219 
220 	// init the repl
221 	Replxx rx;
222 	Tick tick( rx, argc_ > 1 ? argv_[1] : "" );
223 	rx.install_window_change_handler();
224 
225 	// the path to the history file
226 	std::string history_file {"./replxx_history.txt"};
227 
228 	// load the history file if it exists
229 	rx.history_load(history_file);
230 
231 	// set the max history size
232 	rx.set_max_history_size(128);
233 
234 	// set the max number of hint rows to show
235 	rx.set_max_hint_rows(3);
236 
237 	// set the callbacks
238 	using namespace std::placeholders;
239 	rx.set_completion_callback( std::bind( &hook_completion, _1, _2, cref( examples ) ) );
240 	rx.set_highlighter_callback( std::bind( &hook_color, _1, _2, cref( regex_color ) ) );
241 	rx.set_hint_callback( std::bind( &hook_hint, _1, _2, _3, cref( examples ) ) );
242 
243 	// other api calls
244 	rx.set_word_break_characters( " \t.,-%!;:=*~^'\"/?<>|[](){}" );
245 	rx.set_completion_count_cutoff( 128 );
246 	rx.set_double_tab_completion( false );
247 	rx.set_complete_on_empty( true );
248 	rx.set_beep_on_ambiguous_completion( false );
249 	rx.set_no_color( false );
250 
251 	// showcase key bindings
252 	rx.bind_key_internal( Replxx::KEY::BACKSPACE,                      "delete_character_left_of_cursor" );
253 	rx.bind_key_internal( Replxx::KEY::DELETE,                         "delete_character_under_cursor" );
254 	rx.bind_key_internal( Replxx::KEY::LEFT,                           "move_cursor_left" );
255 	rx.bind_key_internal( Replxx::KEY::RIGHT,                          "move_cursor_right" );
256 	rx.bind_key_internal( Replxx::KEY::UP,                             "history_previous" );
257 	rx.bind_key_internal( Replxx::KEY::DOWN,                           "history_next" );
258 	rx.bind_key_internal( Replxx::KEY::PAGE_UP,                        "history_first" );
259 	rx.bind_key_internal( Replxx::KEY::PAGE_DOWN,                      "history_last" );
260 	rx.bind_key_internal( Replxx::KEY::HOME,                           "move_cursor_to_begining_of_line" );
261 	rx.bind_key_internal( Replxx::KEY::END,                            "move_cursor_to_end_of_line" );
262 	rx.bind_key_internal( Replxx::KEY::TAB,                            "complete_line" );
263 	rx.bind_key_internal( Replxx::KEY::control( Replxx::KEY::LEFT ),   "move_cursor_one_word_left" );
264 	rx.bind_key_internal( Replxx::KEY::control( Replxx::KEY::RIGHT ),  "move_cursor_one_word_right" );
265 	rx.bind_key_internal( Replxx::KEY::control( Replxx::KEY::UP ),     "hint_previous" );
266 	rx.bind_key_internal( Replxx::KEY::control( Replxx::KEY::DOWN ),   "hint_next" );
267 	rx.bind_key_internal( Replxx::KEY::control( Replxx::KEY::ENTER ),  "commit_line" );
268 	rx.bind_key_internal( Replxx::KEY::control( 'R' ),                 "history_incremental_search" );
269 	rx.bind_key_internal( Replxx::KEY::control( 'W' ),                 "kill_to_begining_of_word" );
270 	rx.bind_key_internal( Replxx::KEY::control( 'U' ),                 "kill_to_begining_of_line" );
271 	rx.bind_key_internal( Replxx::KEY::control( 'K' ),                 "kill_to_end_of_line" );
272 	rx.bind_key_internal( Replxx::KEY::control( 'Y' ),                 "yank" );
273 	rx.bind_key_internal( Replxx::KEY::control( 'L' ),                 "clear_screen" );
274 	rx.bind_key_internal( Replxx::KEY::control( 'D' ),                 "send_eof" );
275 	rx.bind_key_internal( Replxx::KEY::control( 'C' ),                 "abort_line" );
276 	rx.bind_key_internal( Replxx::KEY::control( 'T' ),                 "transpose_characters" );
277 #ifndef _WIN32
278 	rx.bind_key_internal( Replxx::KEY::control( 'V' ),                 "verbatim_insert" );
279 	rx.bind_key_internal( Replxx::KEY::control( 'Z' ),                 "suspend" );
280 #endif
281 	rx.bind_key_internal( Replxx::KEY::meta( Replxx::KEY::BACKSPACE ), "kill_to_whitespace_on_left" );
282 	rx.bind_key_internal( Replxx::KEY::meta( 'p' ),                    "history_common_prefix_search" );
283 	rx.bind_key_internal( Replxx::KEY::meta( 'n' ),                    "history_common_prefix_search" );
284 	rx.bind_key_internal( Replxx::KEY::meta( 'd' ),                    "kill_to_end_of_word" );
285 	rx.bind_key_internal( Replxx::KEY::meta( 'y' ),                    "yank_cycle" );
286 	rx.bind_key_internal( Replxx::KEY::meta( 'u' ),                    "uppercase_word" );
287 	rx.bind_key_internal( Replxx::KEY::meta( 'l' ),                    "lowercase_word" );
288 	rx.bind_key_internal( Replxx::KEY::meta( 'c' ),                    "capitalize_word" );
289 	rx.bind_key_internal( 'a',                                         "insert_character" );
290 	rx.bind_key_internal( Replxx::KEY::INSERT,                         "toggle_overwrite_mode" );
291 	rx.bind_key( Replxx::KEY::F1, std::bind( &message, std::ref( rx ), "<F1>", _1 ) );
292 	rx.bind_key( Replxx::KEY::F2, std::bind( &message, std::ref( rx ), "<F2>", _1 ) );
293 	rx.bind_key( Replxx::KEY::F3, std::bind( &message, std::ref( rx ), "<F3>", _1 ) );
294 	rx.bind_key( Replxx::KEY::F4, std::bind( &message, std::ref( rx ), "<F4>", _1 ) );
295 	rx.bind_key( Replxx::KEY::F5, std::bind( &message, std::ref( rx ), "<F5>", _1 ) );
296 	rx.bind_key( Replxx::KEY::F6, std::bind( &message, std::ref( rx ), "<F6>", _1 ) );
297 	rx.bind_key( Replxx::KEY::F7, std::bind( &message, std::ref( rx ), "<F7>", _1 ) );
298 	rx.bind_key( Replxx::KEY::F8, std::bind( &message, std::ref( rx ), "<F8>", _1 ) );
299 	rx.bind_key( Replxx::KEY::F9, std::bind( &message, std::ref( rx ), "<F9>", _1 ) );
300 	rx.bind_key( Replxx::KEY::F10, std::bind( &message, std::ref( rx ), "<F10>", _1 ) );
301 	rx.bind_key( Replxx::KEY::F11, std::bind( &message, std::ref( rx ), "<F11>", _1 ) );
302 	rx.bind_key( Replxx::KEY::F12, std::bind( &message, std::ref( rx ), "<F12>", _1 ) );
303 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F1 ), std::bind( &message, std::ref( rx ), "<S-F1>", _1 ) );
304 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F2 ), std::bind( &message, std::ref( rx ), "<S-F2>", _1 ) );
305 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F3 ), std::bind( &message, std::ref( rx ), "<S-F3>", _1 ) );
306 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F4 ), std::bind( &message, std::ref( rx ), "<S-F4>", _1 ) );
307 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F5 ), std::bind( &message, std::ref( rx ), "<S-F5>", _1 ) );
308 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F6 ), std::bind( &message, std::ref( rx ), "<S-F6>", _1 ) );
309 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F7 ), std::bind( &message, std::ref( rx ), "<S-F7>", _1 ) );
310 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F8 ), std::bind( &message, std::ref( rx ), "<S-F8>", _1 ) );
311 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F9 ), std::bind( &message, std::ref( rx ), "<S-F9>", _1 ) );
312 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F10 ), std::bind( &message, std::ref( rx ), "<S-F10>", _1 ) );
313 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F11 ), std::bind( &message, std::ref( rx ), "<S-F11>", _1 ) );
314 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::F12 ), std::bind( &message, std::ref( rx ), "<S-F12>", _1 ) );
315 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F1 ), std::bind( &message, std::ref( rx ), "<C-F1>", _1 ) );
316 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F2 ), std::bind( &message, std::ref( rx ), "<C-F2>", _1 ) );
317 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F3 ), std::bind( &message, std::ref( rx ), "<C-F3>", _1 ) );
318 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F4 ), std::bind( &message, std::ref( rx ), "<C-F4>", _1 ) );
319 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F5 ), std::bind( &message, std::ref( rx ), "<C-F5>", _1 ) );
320 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F6 ), std::bind( &message, std::ref( rx ), "<C-F6>", _1 ) );
321 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F7 ), std::bind( &message, std::ref( rx ), "<C-F7>", _1 ) );
322 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F8 ), std::bind( &message, std::ref( rx ), "<C-F8>", _1 ) );
323 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F9 ), std::bind( &message, std::ref( rx ), "<C-F9>", _1 ) );
324 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F10 ), std::bind( &message, std::ref( rx ), "<C-F10>", _1 ) );
325 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F11 ), std::bind( &message, std::ref( rx ), "<C-F11>", _1 ) );
326 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::F12 ), std::bind( &message, std::ref( rx ), "<C-F12>", _1 ) );
327 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::TAB ), std::bind( &message, std::ref( rx ), "<S-Tab>", _1 ) );
328 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::HOME ), std::bind( &message, std::ref( rx ), "<C-Home>", _1 ) );
329 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::HOME ), std::bind( &message, std::ref( rx ), "<S-Home>", _1 ) );
330 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::END ), std::bind( &message, std::ref( rx ), "<C-End>", _1 ) );
331 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::END ), std::bind( &message, std::ref( rx ), "<S-End>", _1 ) );
332 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::PAGE_UP ), std::bind( &message, std::ref( rx ), "<C-PgUp>", _1 ) );
333 	rx.bind_key( Replxx::KEY::control( Replxx::KEY::PAGE_DOWN ), std::bind( &message, std::ref( rx ), "<C-PgDn>", _1 ) );
334 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::LEFT ), std::bind( &message, std::ref( rx ), "<S-Left>", _1 ) );
335 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::RIGHT ), std::bind( &message, std::ref( rx ), "<S-Right>", _1 ) );
336 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::UP ), std::bind( &message, std::ref( rx ), "<S-Up>", _1 ) );
337 	rx.bind_key( Replxx::KEY::shift( Replxx::KEY::DOWN ), std::bind( &message, std::ref( rx ), "<S-Down>", _1 ) );
338 
339 	// display initial welcome message
340 	std::cout
341 		<< "Welcome to Replxx\n"
342 		<< "Press 'tab' to view autocompletions\n"
343 		<< "Type '.help' for help\n"
344 		<< "Type '.quit' or '.exit' to exit\n\n";
345 
346 	// set the repl prompt
347 	std::string prompt {"\x1b[1;32mreplxx\x1b[0m> "};
348 
349 	// main repl loop
350 	if ( argc_ > 1 ) {
351 		tick.start();
352 	}
353 	for (;;) {
354 		// display the prompt and retrieve input from the user
355 		char const* cinput{ nullptr };
356 
357 		do {
358 			cinput = rx.input(prompt);
359 		} while ( ( cinput == nullptr ) && ( errno == EAGAIN ) );
360 
361 		if (cinput == nullptr) {
362 			break;
363 		}
364 
365 		// change cinput into a std::string
366 		// easier to manipulate
367 		std::string input {cinput};
368 
369 		if (input.empty()) {
370 			// user hit enter on an empty line
371 
372 			continue;
373 
374 		} else if (input.compare(0, 5, ".quit") == 0 || input.compare(0, 5, ".exit") == 0) {
375 			// exit the repl
376 
377 			rx.history_add(input);
378 			break;
379 
380 		} else if (input.compare(0, 5, ".help") == 0) {
381 			// display the help output
382 			std::cout
383 				<< ".help\n\tdisplays the help output\n"
384 				<< ".quit\n\texit the repl\n"
385 				<< ".exit\n\texit the repl\n"
386 				<< ".clear\n\tclears the screen\n"
387 				<< ".history\n\tdisplays the history output\n"
388 				<< ".prompt <str>\n\tset the repl prompt to <str>\n";
389 
390 			rx.history_add(input);
391 			continue;
392 
393 		} else if (input.compare(0, 7, ".prompt") == 0) {
394 			// set the repl prompt text
395 			auto pos = input.find(" ");
396 			if (pos == std::string::npos) {
397 				std::cout << "Error: '.prompt' missing argument\n";
398 			} else {
399 				prompt = input.substr(pos + 1) + " ";
400 			}
401 
402 			rx.history_add(input);
403 			continue;
404 
405 		} else if (input.compare(0, 8, ".history") == 0) {
406 			// display the current history
407 			Replxx::HistoryScan hs( rx.history_scan() );
408 			for ( int i( 0 ); hs.next(); ++ i ) {
409 				std::cout << std::setw(4) << i << ": " << hs.get().text() << "\n";
410 			}
411 
412 			rx.history_add(input);
413 			continue;
414 
415 		} else if (input.compare(0, 6, ".merge") == 0) {
416 			history_file = "replxx_history_alt.txt";
417 
418 			rx.history_add(input);
419 			continue;
420 
421 		} else if (input.compare(0, 6, ".clear") == 0) {
422 			// clear the screen
423 			rx.clear_screen();
424 
425 			rx.history_add(input);
426 			continue;
427 
428 		} else {
429 			// default action
430 			// echo the input
431 
432 			rx.print( "%s\n", input.c_str() );
433 
434 			rx.history_add( input );
435 			continue;
436 		}
437 	}
438 	if ( argc_ > 1 ) {
439 		tick.stop();
440 	}
441 
442 	// save the history
443 	rx.history_save(history_file);
444 
445 	std::cout << "\nExiting Replxx\n";
446 
447 	return 0;
448 }
449