1 /*
2 * Copyright (c) 2017-2018, Marcin Konarski (amok at codestation.org)
3 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
4 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Redis nor the names of its contributors may be used
17 * to endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * line editing lib needs to be 20,000 lines of C code.
33 *
34 * You can find the latest source code at:
35 *
36 * http://github.com/antirez/linenoise
37 *
38 * Does a number of crazy assumptions that happen to be true in 99.9999% of
39 * the 2010 UNIX computers around.
40 *
41 * References:
42 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
43 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
44 *
45 * Todo list:
46 * - Switch to gets() if $TERM is something we can't support.
47 * - Filter bogus Ctrl+<char> combinations.
48 * - Win32 support
49 *
50 * Bloat:
51 * - Completion?
52 * - History search like Ctrl+r in readline?
53 *
54 * List of escape sequences used by this program, we do everything just
55 * with three sequences. In order to be so cheap we may have some
56 * flickering effect with some slow terminal, but the lesser sequences
57 * the more compatible.
58 *
59 * CHA (Cursor Horizontal Absolute)
60 * Sequence: ESC [ n G
61 * Effect: moves cursor to column n (1 based)
62 *
63 * EL (Erase Line)
64 * Sequence: ESC [ n K
65 * Effect: if n is 0 or missing, clear from cursor to end of line
66 * Effect: if n is 1, clear from beginning of line to cursor
67 * Effect: if n is 2, clear entire line
68 *
69 * CUF (Cursor Forward)
70 * Sequence: ESC [ n C
71 * Effect: moves cursor forward of n chars
72 *
73 * The following are used to clear the screen: ESC [ H ESC [ 2 J
74 * This is actually composed of two sequences:
75 *
76 * cursorhome
77 * Sequence: ESC [ H
78 * Effect: moves the cursor to upper left corner
79 *
80 * ED2 (Clear entire screen)
81 * Sequence: ESC [ 2 J
82 * Effect: clear the whole screen
83 *
84 */
85
86 #include <algorithm>
87 #include <cstdarg>
88
89 #ifdef _WIN32
90
91 #include <io.h>
92 #define STDIN_FILENO 0
93
94 #else /* _WIN32 */
95
96 #include <signal.h>
97 #include <unistd.h>
98 #include <sys/stat.h>
99
100 #endif /* _WIN32 */
101
102 #include "replxx.h"
103 #include "replxx.hxx"
104 #include "replxx_impl.hxx"
105 #include "history.hxx"
106
107 static_assert(
108 static_cast<int>( replxx::Replxx::ACTION::SEND_EOF ) == static_cast<int>( REPLXX_ACTION_SEND_EOF ),
109 "C and C++ `ACTION` APIs are missaligned!"
110 );
111
112 static_assert(
113 static_cast<int>( replxx::Replxx::KEY::PASTE_FINISH ) == static_cast<int>( REPLXX_KEY_PASTE_FINISH ),
114 "C and C++ `KEY` APIs are missaligned!"
115 );
116
117 using namespace std;
118 using namespace std::placeholders;
119 using namespace replxx;
120
121 namespace replxx {
122
123 namespace {
delete_ReplxxImpl(Replxx::ReplxxImpl * impl_)124 void delete_ReplxxImpl( Replxx::ReplxxImpl* impl_ ) {
125 delete impl_;
126 }
127 }
128
Replxx(void)129 Replxx::Replxx( void )
130 : _impl( new Replxx::ReplxxImpl( nullptr, nullptr, nullptr ), delete_ReplxxImpl ) {
131 }
132
set_completion_callback(completion_callback_t const & fn)133 void Replxx::set_completion_callback( completion_callback_t const& fn ) {
134 _impl->set_completion_callback( fn );
135 }
136
set_modify_callback(modify_callback_t const & fn)137 void Replxx::set_modify_callback( modify_callback_t const& fn ) {
138 _impl->set_modify_callback( fn );
139 }
140
set_highlighter_callback(highlighter_callback_t const & fn)141 void Replxx::set_highlighter_callback( highlighter_callback_t const& fn ) {
142 _impl->set_highlighter_callback( fn );
143 }
144
set_hint_callback(hint_callback_t const & fn)145 void Replxx::set_hint_callback( hint_callback_t const& fn ) {
146 _impl->set_hint_callback( fn );
147 }
148
input(std::string const & prompt)149 char const* Replxx::input( std::string const& prompt ) {
150 return ( _impl->input( prompt ) );
151 }
152
history_add(std::string const & line)153 void Replxx::history_add( std::string const& line ) {
154 _impl->history_add( line );
155 }
156
history_sync(std::string const & filename)157 bool Replxx::history_sync( std::string const& filename ) {
158 return ( _impl->history_sync( filename ) );
159 }
160
history_save(std::string const & filename)161 bool Replxx::history_save( std::string const& filename ) {
162 return ( _impl->history_save( filename ) );
163 }
164
history_load(std::string const & filename)165 bool Replxx::history_load( std::string const& filename ) {
166 return ( _impl->history_load( filename ) );
167 }
168
history_clear(void)169 void Replxx::history_clear( void ) {
170 _impl->history_clear();
171 }
172
history_size(void) const173 int Replxx::history_size( void ) const {
174 return ( _impl->history_size() );
175 }
176
history_scan(void) const177 Replxx::HistoryScan Replxx::history_scan( void ) const {
178 return ( _impl->history_scan() );
179 }
180
set_preload_buffer(std::string const & preloadText)181 void Replxx::set_preload_buffer( std::string const& preloadText ) {
182 _impl->set_preload_buffer( preloadText );
183 }
184
set_word_break_characters(char const * wordBreakers)185 void Replxx::set_word_break_characters( char const* wordBreakers ) {
186 _impl->set_word_break_characters( wordBreakers );
187 }
188
set_max_hint_rows(int count)189 void Replxx::set_max_hint_rows( int count ) {
190 _impl->set_max_hint_rows( count );
191 }
192
set_hint_delay(int milliseconds)193 void Replxx::set_hint_delay( int milliseconds ) {
194 _impl->set_hint_delay( milliseconds );
195 }
196
set_completion_count_cutoff(int count)197 void Replxx::set_completion_count_cutoff( int count ) {
198 _impl->set_completion_count_cutoff( count );
199 }
200
set_double_tab_completion(bool val)201 void Replxx::set_double_tab_completion( bool val ) {
202 _impl->set_double_tab_completion( val );
203 }
204
set_complete_on_empty(bool val)205 void Replxx::set_complete_on_empty( bool val ) {
206 _impl->set_complete_on_empty( val );
207 }
208
set_beep_on_ambiguous_completion(bool val)209 void Replxx::set_beep_on_ambiguous_completion( bool val ) {
210 _impl->set_beep_on_ambiguous_completion( val );
211 }
212
set_immediate_completion(bool val)213 void Replxx::set_immediate_completion( bool val ) {
214 _impl->set_immediate_completion( val );
215 }
216
set_unique_history(bool val)217 void Replxx::set_unique_history( bool val ) {
218 _impl->set_unique_history( val );
219 }
220
set_no_color(bool val)221 void Replxx::set_no_color( bool val ) {
222 _impl->set_no_color( val );
223 }
224
set_max_history_size(int len)225 void Replxx::set_max_history_size( int len ) {
226 _impl->set_max_history_size( len );
227 }
228
clear_screen(void)229 void Replxx::clear_screen( void ) {
230 _impl->clear_screen( 0 );
231 }
232
emulate_key_press(char32_t keyPress_)233 void Replxx::emulate_key_press( char32_t keyPress_ ) {
234 _impl->emulate_key_press( keyPress_ );
235 }
236
invoke(ACTION action_,char32_t keyPress_)237 Replxx::ACTION_RESULT Replxx::invoke( ACTION action_, char32_t keyPress_ ) {
238 return ( _impl->invoke( action_, keyPress_ ) );
239 }
240
bind_key(char32_t keyPress_,key_press_handler_t handler_)241 void Replxx::bind_key( char32_t keyPress_, key_press_handler_t handler_ ) {
242 _impl->bind_key( keyPress_, handler_ );
243 }
244
bind_key_internal(char32_t keyPress_,char const * actionName_)245 void Replxx::bind_key_internal( char32_t keyPress_, char const* actionName_ ) {
246 _impl->bind_key_internal( keyPress_, actionName_ );
247 }
248
get_state(void) const249 Replxx::State Replxx::get_state( void ) const {
250 return ( _impl->get_state() );
251 }
252
set_state(Replxx::State const & state_)253 void Replxx::set_state( Replxx::State const& state_ ) {
254 _impl->set_state( state_ );
255 }
256
install_window_change_handler(void)257 int Replxx::install_window_change_handler( void ) {
258 return ( _impl->install_window_change_handler() );
259 }
260
enable_bracketed_paste(void)261 void Replxx::enable_bracketed_paste( void ) {
262 _impl->enable_bracketed_paste();
263 }
264
disable_bracketed_paste(void)265 void Replxx::disable_bracketed_paste( void ) {
266 _impl->disable_bracketed_paste();
267 }
268
print(char const * format_,...)269 void Replxx::print( char const* format_, ... ) {
270 ::std::va_list ap;
271 va_start( ap, format_ );
272 int size = static_cast<int>( vsnprintf( nullptr, 0, format_, ap ) );
273 va_end( ap );
274 va_start( ap, format_ );
275 unique_ptr<char[]> buf( new char[size + 1] );
276 vsnprintf( buf.get(), static_cast<size_t>( size + 1 ), format_, ap );
277 va_end( ap );
278 return ( _impl->print( buf.get(), size ) );
279 }
280
write(char const * str,int length)281 void Replxx::write( char const* str, int length ) {
282 return ( _impl->print( str, length ) );
283 }
284
285 }
286
replxx_init()287 ::Replxx* replxx_init() {
288 typedef ::Replxx* replxx_data_t;
289 return ( reinterpret_cast<replxx_data_t>( new replxx::Replxx::ReplxxImpl( nullptr, nullptr, nullptr ) ) );
290 }
291
replxx_end(::Replxx * replxx_)292 void replxx_end( ::Replxx* replxx_ ) {
293 delete reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ );
294 }
295
replxx_clear_screen(::Replxx * replxx_)296 void replxx_clear_screen( ::Replxx* replxx_ ) {
297 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
298 replxx->clear_screen( 0 );
299 }
300
replxx_emulate_key_press(::Replxx * replxx_,int unsigned keyPress_)301 void replxx_emulate_key_press( ::Replxx* replxx_, int unsigned keyPress_ ) {
302 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
303 replxx->emulate_key_press( keyPress_ );
304 }
305
replxx_invoke(::Replxx * replxx_,ReplxxAction action_,int unsigned keyPress_)306 ReplxxActionResult replxx_invoke( ::Replxx* replxx_, ReplxxAction action_, int unsigned keyPress_ ) {
307 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
308 return ( static_cast<ReplxxActionResult>( replxx->invoke( static_cast<replxx::Replxx::ACTION>( action_ ), keyPress_ ) ) );
309 }
310
key_press_handler_forwarder(key_press_handler_t handler_,char32_t code_,void * userData_)311 replxx::Replxx::ACTION_RESULT key_press_handler_forwarder( key_press_handler_t handler_, char32_t code_, void* userData_ ) {
312 return ( static_cast<replxx::Replxx::ACTION_RESULT>( handler_( code_, userData_ ) ) );
313 }
314
replxx_bind_key(::Replxx * replxx_,int code_,key_press_handler_t handler_,void * userData_)315 void replxx_bind_key( ::Replxx* replxx_, int code_, key_press_handler_t handler_, void* userData_ ) {
316 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
317 replxx->bind_key( code_, std::bind( key_press_handler_forwarder, handler_, _1, userData_ ) );
318 }
319
replxx_bind_key_internal(::Replxx * replxx_,int code_,char const * actionName_)320 int replxx_bind_key_internal( ::Replxx* replxx_, int code_, char const* actionName_ ) {
321 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
322 try {
323 replxx->bind_key_internal( code_, actionName_ );
324 } catch ( ... ) {
325 return ( -1 );
326 }
327 return ( 0 );
328 }
329
replxx_get_state(::Replxx * replxx_,ReplxxState * state)330 void replxx_get_state( ::Replxx* replxx_, ReplxxState* state ) {
331 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
332 replxx::Replxx::State s( replxx->get_state() );
333 state->text = s.text();
334 state->cursorPosition = s.cursor_position();
335 }
336
replxx_set_state(::Replxx * replxx_,ReplxxState * state)337 void replxx_set_state( ::Replxx* replxx_, ReplxxState* state ) {
338 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
339 replxx->set_state( replxx::Replxx::State( state->text, state->cursorPosition ) );
340 }
341
342 /**
343 * replxx_set_preload_buffer provides text to be inserted into the command buffer
344 *
345 * the provided text will be processed to be usable and will be used to preload
346 * the input buffer on the next call to replxx_input()
347 *
348 * @param preloadText text to begin with on the next call to replxx_input()
349 */
replxx_set_preload_buffer(::Replxx * replxx_,const char * preloadText)350 void replxx_set_preload_buffer(::Replxx* replxx_, const char* preloadText) {
351 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
352 replxx->set_preload_buffer( preloadText ? preloadText : "" );
353 }
354
355 /**
356 * replxx_input is a readline replacement.
357 *
358 * call it with a prompt to display and it will return a line of input from the
359 * user
360 *
361 * @param prompt text of prompt to display to the user
362 * @return the returned string is managed by replxx library
363 * and it must NOT be freed in the client.
364 */
replxx_input(::Replxx * replxx_,const char * prompt)365 char const* replxx_input( ::Replxx* replxx_, const char* prompt ) {
366 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
367 return ( replxx->input( prompt ) );
368 }
369
replxx_print(::Replxx * replxx_,char const * format_,...)370 int replxx_print( ::Replxx* replxx_, char const* format_, ... ) {
371 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
372 ::std::va_list ap;
373 va_start( ap, format_ );
374 int size = static_cast<int>( vsnprintf( nullptr, 0, format_, ap ) );
375 va_end( ap );
376 va_start( ap, format_ );
377 unique_ptr<char[]> buf( new char[size + 1] );
378 vsnprintf( buf.get(), static_cast<size_t>( size + 1 ), format_, ap );
379 va_end( ap );
380 try {
381 replxx->print( buf.get(), size );
382 } catch ( ... ) {
383 return ( -1 );
384 }
385 return ( size );
386 }
387
replxx_write(::Replxx * replxx_,char const * str,int length)388 int replxx_write( ::Replxx* replxx_, char const* str, int length ) {
389 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
390 try {
391 replxx->print( str, length );
392 } catch ( ... ) {
393 return ( -1 );
394 }
395 return static_cast<int>( length );
396 }
397
398 struct replxx_completions {
399 replxx::Replxx::completions_t data;
400 };
401
402 struct replxx_hints {
403 replxx::Replxx::hints_t data;
404 };
405
modify_fwd(replxx_modify_callback_t fn,std::string & line_,int & cursorPosition_,void * userData_)406 void modify_fwd( replxx_modify_callback_t fn, std::string& line_, int& cursorPosition_, void* userData_ ) {
407 #ifdef _WIN32
408 #define strdup _strdup
409 #endif
410 char* s( strdup( line_.c_str() ) );
411 #undef strdup
412 fn( &s, &cursorPosition_, userData_ );
413 line_ = s;
414 free( s );
415 return;
416 }
417
replxx_set_modify_callback(::Replxx * replxx_,replxx_modify_callback_t * fn,void * userData)418 void replxx_set_modify_callback(::Replxx* replxx_, replxx_modify_callback_t* fn, void* userData) {
419 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
420 replxx->set_modify_callback( std::bind( &modify_fwd, fn, _1, _2, userData ) );
421 }
422
completions_fwd(replxx_completion_callback_t fn,std::string const & input_,int & contextLen_,void * userData)423 replxx::Replxx::completions_t completions_fwd( replxx_completion_callback_t fn, std::string const& input_, int& contextLen_, void* userData ) {
424 replxx_completions completions;
425 fn( input_.c_str(), &completions, &contextLen_, userData );
426 return ( completions.data );
427 }
428
429 /* Register a callback function to be called for tab-completion. */
replxx_set_completion_callback(::Replxx * replxx_,replxx_completion_callback_t * fn,void * userData)430 void replxx_set_completion_callback(::Replxx* replxx_, replxx_completion_callback_t* fn, void* userData) {
431 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
432 replxx->set_completion_callback( std::bind( &completions_fwd, fn, _1, _2, userData ) );
433 }
434
highlighter_fwd(replxx_highlighter_callback_t fn,std::string const & input,replxx::Replxx::colors_t & colors,void * userData)435 void highlighter_fwd( replxx_highlighter_callback_t fn, std::string const& input, replxx::Replxx::colors_t& colors, void* userData ) {
436 std::vector<ReplxxColor> colorsTmp( colors.size() );
437 std::transform(
438 colors.begin(),
439 colors.end(),
440 colorsTmp.begin(),
441 []( replxx::Replxx::Color c ) {
442 return ( static_cast<ReplxxColor>( c ) );
443 }
444 );
445 fn( input.c_str(), colorsTmp.data(), static_cast<int>( colors.size() ), userData );
446 std::transform(
447 colorsTmp.begin(),
448 colorsTmp.end(),
449 colors.begin(),
450 []( ReplxxColor c ) {
451 return ( static_cast<replxx::Replxx::Color>( c ) );
452 }
453 );
454 }
455
replxx_set_highlighter_callback(::Replxx * replxx_,replxx_highlighter_callback_t * fn,void * userData)456 void replxx_set_highlighter_callback( ::Replxx* replxx_, replxx_highlighter_callback_t* fn, void* userData ) {
457 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
458 replxx->set_highlighter_callback( std::bind( &highlighter_fwd, fn, _1, _2, userData ) );
459 }
460
hints_fwd(replxx_hint_callback_t fn,std::string const & input_,int & contextLen_,replxx::Replxx::Color & color_,void * userData)461 replxx::Replxx::hints_t hints_fwd( replxx_hint_callback_t fn, std::string const& input_, int& contextLen_, replxx::Replxx::Color& color_, void* userData ) {
462 replxx_hints hints;
463 ReplxxColor c( static_cast<ReplxxColor>( color_ ) );
464 fn( input_.c_str(), &hints, &contextLen_, &c, userData );
465 return ( hints.data );
466 }
467
replxx_set_hint_callback(::Replxx * replxx_,replxx_hint_callback_t * fn,void * userData)468 void replxx_set_hint_callback( ::Replxx* replxx_, replxx_hint_callback_t* fn, void* userData ) {
469 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
470 replxx->set_hint_callback( std::bind( &hints_fwd, fn, _1, _2, _3, userData ) );
471 }
472
replxx_add_hint(replxx_hints * lh,const char * str)473 void replxx_add_hint(replxx_hints* lh, const char* str) {
474 lh->data.emplace_back(str);
475 }
476
replxx_add_completion(replxx_completions * lc,const char * str)477 void replxx_add_completion( replxx_completions* lc, const char* str ) {
478 lc->data.emplace_back( str );
479 }
480
replxx_add_color_completion(replxx_completions * lc,const char * str,ReplxxColor color)481 void replxx_add_color_completion( replxx_completions* lc, const char* str, ReplxxColor color ) {
482 lc->data.emplace_back( str, static_cast<replxx::Replxx::Color>( color ) );
483 }
484
replxx_history_add(::Replxx * replxx_,const char * line)485 void replxx_history_add( ::Replxx* replxx_, const char* line ) {
486 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
487 replxx->history_add( line );
488 }
489
replxx_set_max_history_size(::Replxx * replxx_,int len)490 void replxx_set_max_history_size( ::Replxx* replxx_, int len ) {
491 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
492 replxx->set_max_history_size( len );
493 }
494
replxx_set_max_hint_rows(::Replxx * replxx_,int count)495 void replxx_set_max_hint_rows( ::Replxx* replxx_, int count ) {
496 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
497 replxx->set_max_hint_rows( count );
498 }
499
replxx_set_hint_delay(::Replxx * replxx_,int milliseconds)500 void replxx_set_hint_delay( ::Replxx* replxx_, int milliseconds ) {
501 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
502 replxx->set_hint_delay( milliseconds );
503 }
504
replxx_set_completion_count_cutoff(::Replxx * replxx_,int count)505 void replxx_set_completion_count_cutoff( ::Replxx* replxx_, int count ) {
506 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
507 replxx->set_completion_count_cutoff( count );
508 }
509
replxx_set_word_break_characters(::Replxx * replxx_,char const * breakChars_)510 void replxx_set_word_break_characters( ::Replxx* replxx_, char const* breakChars_ ) {
511 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
512 replxx->set_word_break_characters( breakChars_ );
513 }
514
replxx_set_double_tab_completion(::Replxx * replxx_,int val)515 void replxx_set_double_tab_completion( ::Replxx* replxx_, int val ) {
516 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
517 replxx->set_double_tab_completion( val ? true : false );
518 }
519
replxx_set_complete_on_empty(::Replxx * replxx_,int val)520 void replxx_set_complete_on_empty( ::Replxx* replxx_, int val ) {
521 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
522 replxx->set_complete_on_empty( val ? true : false );
523 }
524
replxx_set_no_color(::Replxx * replxx_,int val)525 void replxx_set_no_color( ::Replxx* replxx_, int val ) {
526 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
527 replxx->set_no_color( val ? true : false );
528 }
529
replxx_set_beep_on_ambiguous_completion(::Replxx * replxx_,int val)530 void replxx_set_beep_on_ambiguous_completion( ::Replxx* replxx_, int val ) {
531 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
532 replxx->set_beep_on_ambiguous_completion( val ? true : false );
533 }
534
replxx_set_immediate_completion(::Replxx * replxx_,int val)535 void replxx_set_immediate_completion( ::Replxx* replxx_, int val ) {
536 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
537 replxx->set_immediate_completion( val ? true : false );
538 }
539
replxx_set_unique_history(::Replxx * replxx_,int val)540 void replxx_set_unique_history( ::Replxx* replxx_, int val ) {
541 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
542 replxx->set_unique_history( val ? true : false );
543 }
544
replxx_enable_bracketed_paste(::Replxx * replxx_)545 void replxx_enable_bracketed_paste( ::Replxx* replxx_ ) {
546 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
547 replxx->enable_bracketed_paste();
548 }
549
replxx_disable_bracketed_paste(::Replxx * replxx_)550 void replxx_disable_bracketed_paste( ::Replxx* replxx_ ) {
551 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
552 replxx->disable_bracketed_paste();
553 }
554
replxx_history_scan_start(::Replxx * replxx_)555 ReplxxHistoryScan* replxx_history_scan_start( ::Replxx* replxx_ ) {
556 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
557 return ( reinterpret_cast<ReplxxHistoryScan*>( replxx->history_scan().release() ) );
558 }
559
replxx_history_scan_stop(::Replxx *,ReplxxHistoryScan * historyScan_)560 void replxx_history_scan_stop( ::Replxx*, ReplxxHistoryScan* historyScan_ ) {
561 delete reinterpret_cast<replxx::Replxx::HistoryScanImpl*>( historyScan_ );
562 }
563
replxx_history_scan_next(::Replxx *,ReplxxHistoryScan * historyScan_,ReplxxHistoryEntry * historyEntry_)564 int replxx_history_scan_next( ::Replxx*, ReplxxHistoryScan* historyScan_, ReplxxHistoryEntry* historyEntry_ ) {
565 replxx::Replxx::HistoryScanImpl* historyScan( reinterpret_cast<replxx::Replxx::HistoryScanImpl*>( historyScan_ ) );
566 bool hasNext( historyScan->next() );
567 if ( hasNext ) {
568 replxx::Replxx::HistoryEntry const& historyEntry( historyScan->get() );
569 historyEntry_->timestamp = historyEntry.timestamp().c_str();
570 historyEntry_->text = historyEntry.text().c_str();
571 }
572 return ( hasNext ? 0 : -1 );
573 }
574
575 /* Save the history in the specified file. On success 0 is returned
576 * otherwise -1 is returned. */
replxx_history_sync(::Replxx * replxx_,const char * filename)577 int replxx_history_sync( ::Replxx* replxx_, const char* filename ) {
578 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
579 return ( replxx->history_sync( filename ) ? 0 : -1 );
580 }
581
582 /* Save the history in the specified file. On success 0 is returned
583 * otherwise -1 is returned. */
replxx_history_save(::Replxx * replxx_,const char * filename)584 int replxx_history_save( ::Replxx* replxx_, const char* filename ) {
585 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
586 return ( replxx->history_save( filename ) ? 0 : -1 );
587 }
588
589 /* Load the history from the specified file. If the file does not exist
590 * zero is returned and no operation is performed.
591 *
592 * If the file exists and the operation succeeded 0 is returned, otherwise
593 * on error -1 is returned. */
replxx_history_load(::Replxx * replxx_,const char * filename)594 int replxx_history_load( ::Replxx* replxx_, const char* filename ) {
595 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
596 return ( replxx->history_load( filename ) ? 0 : -1 );
597 }
598
replxx_history_clear(::Replxx * replxx_)599 void replxx_history_clear( ::Replxx* replxx_ ) {
600 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
601 replxx->history_clear();
602 }
603
replxx_history_size(::Replxx * replxx_)604 int replxx_history_size( ::Replxx* replxx_ ) {
605 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
606 return ( replxx->history_size() );
607 }
608
609 /* This special mode is used by replxx in order to print scan codes
610 * on screen for debugging / development purposes. It is implemented
611 * by the replxx-c-api-example program using the --keycodes option. */
612 #ifdef __REPLXX_DEBUG__
replxx_debug_dump_print_codes(void)613 void replxx_debug_dump_print_codes(void) {
614 char quit[4];
615
616 printf(
617 "replxx key codes debugging mode.\n"
618 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
619 if (enableRawMode() == -1) return;
620 memset(quit, ' ', 4);
621 while (1) {
622 char c;
623 int nread;
624
625 #if _WIN32
626 nread = _read(STDIN_FILENO, &c, 1);
627 #else
628 nread = read(STDIN_FILENO, &c, 1);
629 #endif
630 if (nread <= 0) continue;
631 memmove(quit, quit + 1, sizeof(quit) - 1); /* shift string to left. */
632 quit[sizeof(quit) - 1] = c; /* Insert current char on the right. */
633 if (memcmp(quit, "quit", sizeof(quit)) == 0) break;
634
635 printf("'%c' %02x (%d) (type quit to exit)\n", isprint(c) ? c : '?', (int)c,
636 (int)c);
637 printf("\r"); /* Go left edge manually, we are in raw mode. */
638 fflush(stdout);
639 }
640 disableRawMode();
641 }
642 #endif // __REPLXX_DEBUG__
643
replxx_install_window_change_handler(::Replxx * replxx_)644 int replxx_install_window_change_handler( ::Replxx* replxx_ ) {
645 replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
646 return ( replxx->install_window_change_handler() );
647 }
648
649