diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/replxx/include/replxx.hxx | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/contrib/replxx/include/replxx.hxx b/contrib/replxx/include/replxx.hxx new file mode 100644 index 0000000..5362312 --- /dev/null +++ b/contrib/replxx/include/replxx.hxx @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2017-2018, Marcin Konarski (amok at codestation.org) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAVE_REPLXX_HXX_INCLUDED +#define HAVE_REPLXX_HXX_INCLUDED 1 + +#include <memory> +#include <vector> +#include <string> +#include <functional> + +/* + * For use in Windows DLLs: + * + * If you are building replxx into a DLL, + * unless you are using supplied CMake based build, + * ensure that 'REPLXX_BUILDING_DLL' is defined when + * building the DLL so that proper symbols are exported. + */ +#if defined( _WIN32 ) && ! defined( REPLXX_STATIC ) +# ifdef REPLXX_BUILDING_DLL +# define REPLXX_IMPEXP __declspec( dllexport ) +# else +# define REPLXX_IMPEXP __declspec( dllimport ) +# endif +#else +# define REPLXX_IMPEXP /**/ +#endif + +#ifdef ERROR +enum { ERROR_BB1CA97EC761FC37101737BA0AA2E7C5 = ERROR }; +#undef ERROR +enum { ERROR = ERROR_BB1CA97EC761FC37101737BA0AA2E7C5 }; +#endif +#ifdef DELETE +enum { DELETE_32F68A60CEF40FAEDBC6AF20298C1A1E = DELETE }; +#undef DELETE +enum { DELETE = DELETE_32F68A60CEF40FAEDBC6AF20298C1A1E }; +#endif + +namespace replxx { + +class REPLXX_IMPEXP Replxx { +public: + enum class Color { + BLACK = 0, + RED = 1, + GREEN = 2, + BROWN = 3, + BLUE = 4, + MAGENTA = 5, + CYAN = 6, + LIGHTGRAY = 7, + GRAY = 8, + BRIGHTRED = 9, + BRIGHTGREEN = 10, + YELLOW = 11, + BRIGHTBLUE = 12, + BRIGHTMAGENTA = 13, + BRIGHTCYAN = 14, + WHITE = 15, + NORMAL = LIGHTGRAY, + DEFAULT = -1, + ERROR = -2 + }; + struct KEY { + static char32_t const BASE = 0x0010ffff + 1; + static char32_t const BASE_SHIFT = 0x01000000; + static char32_t const BASE_CONTROL = 0x02000000; + static char32_t const BASE_META = 0x04000000; + static char32_t const ESCAPE = 27; + static char32_t const PAGE_UP = BASE + 1; + static char32_t const PAGE_DOWN = PAGE_UP + 1; + static char32_t const DOWN = PAGE_DOWN + 1; + static char32_t const UP = DOWN + 1; + static char32_t const LEFT = UP + 1; + static char32_t const RIGHT = LEFT + 1; + static char32_t const HOME = RIGHT + 1; + static char32_t const END = HOME + 1; + static char32_t const DELETE = END + 1; + static char32_t const INSERT = DELETE + 1; + static char32_t const F1 = INSERT + 1; + static char32_t const F2 = F1 + 1; + static char32_t const F3 = F2 + 1; + static char32_t const F4 = F3 + 1; + static char32_t const F5 = F4 + 1; + static char32_t const F6 = F5 + 1; + static char32_t const F7 = F6 + 1; + static char32_t const F8 = F7 + 1; + static char32_t const F9 = F8 + 1; + static char32_t const F10 = F9 + 1; + static char32_t const F11 = F10 + 1; + static char32_t const F12 = F11 + 1; + static char32_t const F13 = F12 + 1; + static char32_t const F14 = F13 + 1; + static char32_t const F15 = F14 + 1; + static char32_t const F16 = F15 + 1; + static char32_t const F17 = F16 + 1; + static char32_t const F18 = F17 + 1; + static char32_t const F19 = F18 + 1; + static char32_t const F20 = F19 + 1; + static char32_t const F21 = F20 + 1; + static char32_t const F22 = F21 + 1; + static char32_t const F23 = F22 + 1; + static char32_t const F24 = F23 + 1; + static char32_t const MOUSE = F24 + 1; + static char32_t const PASTE_START = MOUSE + 1; + static char32_t const PASTE_FINISH = PASTE_START + 1; + static constexpr char32_t shift( char32_t key_ ) { + return ( key_ | BASE_SHIFT ); + } + static constexpr char32_t control( char32_t key_ ) { + return ( key_ | BASE_CONTROL ); + } + static constexpr char32_t meta( char32_t key_ ) { + return ( key_ | BASE_META ); + } + static char32_t const BACKSPACE = 'H' | BASE_CONTROL; + static char32_t const TAB = 'I' | BASE_CONTROL; + static char32_t const ENTER = 'M' | BASE_CONTROL; + }; + /*! \brief List of built-in actions that act upon user input. + */ + enum class ACTION { + INSERT_CHARACTER, + NEW_LINE, + DELETE_CHARACTER_UNDER_CURSOR, + DELETE_CHARACTER_LEFT_OF_CURSOR, + KILL_TO_END_OF_LINE, + KILL_TO_BEGINING_OF_LINE, + KILL_TO_END_OF_WORD, + KILL_TO_BEGINING_OF_WORD, + KILL_TO_END_OF_SUBWORD, + KILL_TO_BEGINING_OF_SUBWORD, + KILL_TO_WHITESPACE_ON_LEFT, + YANK, + YANK_CYCLE, + YANK_LAST_ARG, + MOVE_CURSOR_TO_BEGINING_OF_LINE, + MOVE_CURSOR_TO_END_OF_LINE, + MOVE_CURSOR_ONE_WORD_LEFT, + MOVE_CURSOR_ONE_WORD_RIGHT, + MOVE_CURSOR_ONE_SUBWORD_LEFT, + MOVE_CURSOR_ONE_SUBWORD_RIGHT, + MOVE_CURSOR_LEFT, + MOVE_CURSOR_RIGHT, + HISTORY_NEXT, + HISTORY_PREVIOUS, + HISTORY_FIRST, + HISTORY_LAST, + HISTORY_INCREMENTAL_SEARCH, + HISTORY_COMMON_PREFIX_SEARCH, + HINT_NEXT, + HINT_PREVIOUS, + CAPITALIZE_WORD, + LOWERCASE_WORD, + UPPERCASE_WORD, + CAPITALIZE_SUBWORD, + LOWERCASE_SUBWORD, + UPPERCASE_SUBWORD, + TRANSPOSE_CHARACTERS, + TOGGLE_OVERWRITE_MODE, +#ifndef _WIN32 + VERBATIM_INSERT, + SUSPEND, +#endif + BRACKETED_PASTE, + CLEAR_SCREEN, + CLEAR_SELF, + REPAINT, + COMPLETE_LINE, + COMPLETE_NEXT, + COMPLETE_PREVIOUS, + COMMIT_LINE, + ABORT_LINE, + SEND_EOF + }; + /*! \brief Possible results of key-press handler actions. + */ + enum class ACTION_RESULT { + CONTINUE, /*!< Continue processing user input. */ + RETURN, /*!< Return user input entered so far. */ + BAIL /*!< Stop processing user input, returns nullptr from the \e input() call. */ + }; + typedef std::vector<Color> colors_t; + class Completion { + std::string _text; + Color _color; + public: + Completion( char const* text_ ) + : _text( text_ ) + , _color( Color::DEFAULT ) { + } + Completion( std::string const& text_ ) + : _text( text_ ) + , _color( Color::DEFAULT ) { + } + Completion( std::string const& text_, Color color_ ) + : _text( text_ ) + , _color( color_ ) { + } + std::string const& text( void ) const { + return ( _text ); + } + Color color( void ) const { + return ( _color ); + } + }; + typedef std::vector<Completion> completions_t; + class HistoryEntry { + std::string _timestamp; + std::string _text; + public: + HistoryEntry( std::string const& timestamp_, std::string const& text_ ) + : _timestamp( timestamp_ ) + , _text( text_ ) { + } + std::string const& timestamp( void ) const { + return ( _timestamp ); + } + std::string const& text( void ) const { + return ( _text ); + } + }; + class HistoryScanImpl; + class HistoryScan { + public: + typedef std::unique_ptr<HistoryScanImpl, void (*)( HistoryScanImpl* )> impl_t; + private: +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + impl_t _impl; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + public: + HistoryScan( impl_t ); + HistoryScan( HistoryScan&& ) = default; + HistoryScan& operator = ( HistoryScan&& ) = default; + bool next( void ); + HistoryEntry const& get( void ) const; + private: + HistoryScan( HistoryScan const& ) = delete; + HistoryScan& operator = ( HistoryScan const& ) = delete; + }; + typedef std::vector<std::string> hints_t; + + /*! \brief Line modification callback type definition. + * + * User can observe and modify line contents (and cursor position) + * in response to changes to both introduced by the user through + * normal interactions. + * + * When callback returns Replxx updates current line content + * and current cursor position to the ones updated by the callback. + * + * \param line[in,out] - a R/W reference to an UTF-8 encoded input entered by the user so far. + * \param cursorPosition[in,out] - a R/W reference to current cursor position. + */ + typedef std::function<void ( std::string& line, int& cursorPosition )> modify_callback_t; + + /*! \brief Completions callback type definition. + * + * \e contextLen is counted in Unicode code points (not in bytes!). + * + * For user input: + * if ( obj.me + * + * input == "if ( obj.me" + * contextLen == 2 (depending on \e set_word_break_characters()) + * + * Client application is free to update \e contextLen to be 6 (or any other non-negative + * number not greater than the number of code points in input) if it makes better sense + * for given client application semantics. + * + * \param input - UTF-8 encoded input entered by the user until current cursor position. + * \param[in,out] contextLen - length of the additional context to provide while displaying completions. + * \return A list of user completions. + */ + typedef std::function<completions_t ( std::string const& input, int& contextLen )> completion_callback_t; + + /*! \brief Highlighter callback type definition. + * + * If user want to have colorful input she must simply install highlighter callback. + * The callback would be invoked by the library after each change to the input done by + * the user. After callback returns library uses data from colors buffer to colorize + * displayed user input. + * + * Size of \e colors buffer is equal to number of code points in user \e input + * which will be different from simple `input.length()`! + * + * \param input - an UTF-8 encoded input entered by the user so far. + * \param colors - output buffer for color information. + */ + typedef std::function<void ( std::string const& input, colors_t& colors )> highlighter_callback_t; + + /*! \brief Hints callback type definition. + * + * \e contextLen is counted in Unicode code points (not in bytes!). + * + * For user input: + * if ( obj.me + * + * input == "if ( obj.me" + * contextLen == 2 (depending on \e set_word_break_characters()) + * + * Client application is free to update \e contextLen to be 6 (or any other non-negative + * number not greater than the number of code points in input) if it makes better sense + * for given client application semantics. + * + * \param input - UTF-8 encoded input entered by the user until current cursor position. + * \param contextLen[in,out] - length of the additional context to provide while displaying hints. + * \param color - a color used for displaying hints. + * \return A list of possible hints. + */ + typedef std::function<hints_t ( std::string const& input, int& contextLen, Color& color )> hint_callback_t; + + /*! \brief Key press handler type definition. + * + * \param code - the key code replxx got from terminal. + * \return Decision on how should input() behave after this key handler returns. + */ + typedef std::function<ACTION_RESULT ( char32_t code )> key_press_handler_t; + + struct State { + char const* _text; + int _cursorPosition; + State( char const* text_, int cursorPosition_ = -1 ) + : _text( text_ ) + , _cursorPosition( cursorPosition_ ) { + } + State( State const& ) = default; + State& operator = ( State const& ) = default; + char const* text( void ) const { + return ( _text ); + } + int cursor_position( void ) const { + return ( _cursorPosition ); + } + }; + + class ReplxxImpl; +private: + typedef std::unique_ptr<ReplxxImpl, void (*)( ReplxxImpl* )> impl_t; +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + impl_t _impl; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +public: + Replxx( void ); + Replxx( Replxx&& ) = default; + Replxx& operator = ( Replxx&& ) = default; + + /*! \brief Register modify callback. + * + * \param fn - user defined callback function. + */ + void set_modify_callback( modify_callback_t const& fn ); + + /*! \brief Register completion callback. + * + * \param fn - user defined callback function. + */ + void set_completion_callback( completion_callback_t const& fn ); + + /*! \brief Register highlighter callback. + * + * \param fn - user defined callback function. + */ + void set_highlighter_callback( highlighter_callback_t const& fn ); + + /*! \brief Register hints callback. + * + * \param fn - user defined callback function. + */ + void set_hint_callback( hint_callback_t const& fn ); + + /*! \brief Read line of user input. + * + * Returned pointer is managed by the library and is not to be freed in the client. + * + * \param prompt - prompt to be displayed before getting user input. + * \return An UTF-8 encoded input given by the user (or nullptr on EOF). + */ + char const* input( std::string const& prompt ); + + /*! \brief Get current state data. + * + * This call is intended to be used in handlers. + * + * \return Current state of the model. + */ + State get_state( void ) const; + + /*! \brief Set new state data. + * + * This call is intended to be used in handlers. + * + * \param state - new state of the model. + */ + void set_state( State const& state ); + + /*! \brief Print formatted string to standard output. + * + * This function ensures proper handling of ANSI escape sequences + * contained in printed data, which is especially useful on Windows + * since Unixes handle them correctly out of the box. + * + * \param fmt - printf style format. + */ + void print( char const* fmt, ... ); + + /*! \brief Prints a char array with the given length to standard output. + * + * \copydetails print + * + * \param str - The char array to print. + * \param length - The length of the array. + */ + void write( char const* str, int length ); + + /*! \brief Schedule an emulated key press event. + * + * \param code - key press code to be emulated. + */ + void emulate_key_press( char32_t code ); + + /*! \brief Invoke built-in action handler. + * + * \pre This method can be called only from key-press handler. + * + * \param action - a built-in action to invoke. + * \param code - a supplementary key-code to consume by built-in action handler. + * \return The action result informing the replxx what shall happen next. + */ + ACTION_RESULT invoke( ACTION action, char32_t code ); + + /*! \brief Bind user defined action to handle given key-press event. + * + * \param code - handle this key-press event with following handler. + * \param handle - use this handler to handle key-press event. + */ + void bind_key( char32_t code, key_press_handler_t handler ); + + /*! \brief Bind internal `replxx` action (by name) to handle given key-press event. + * + * Action names are the same as names of Replxx::ACTION enumerations + * but in lower case, e.g.: an action for recalling previous history line + * is \e Replxx::ACTION::HISTORY_PREVIOUS so action name to be used in this + * interface for the same effect is "history_previous". + * + * \param code - handle this key-press event with following handler. + * \param actionName - name of internal action to be invoked on key press. + */ + void bind_key_internal( char32_t code, char const* actionName ); + + void history_add( std::string const& line ); + + /*! \brief Synchronize REPL's history with given file. + * + * Synchronizing means loading existing history from given file, + * merging it with current history sorted by timestamps, + * saving merged version to given file, + * keeping merged version as current REPL's history. + * + * This call is an equivalent of calling: + * history_save( "some-file" ); + * history_load( "some-file" ); + * + * \param filename - a path to the file with which REPL's current history should be synchronized. + * \return True iff history file was successfully created. + */ + bool history_sync( std::string const& filename ); + + /*! \brief Save REPL's history into given file. + * + * Saving means loading existing history from given file, + * merging it with current history sorted by timestamps, + * saving merged version to given file, + * keeping original (NOT merged) version as current REPL's history. + * + * \param filename - a path to the file where REPL's history should be saved. + * \return True iff history file was successfully created. + */ + bool history_save( std::string const& filename ); + + /*! \brief Load REPL's history from given file. + * + * \param filename - a path to the file which contains REPL's history that should be loaded. + * \return True iff history file was successfully opened. + */ + bool history_load( std::string const& filename ); + + /*! \brief Clear REPL's in-memory history. + */ + void history_clear( void ); + int history_size( void ) const; + HistoryScan history_scan( void ) const; + + void set_preload_buffer( std::string const& preloadText ); + + /*! \brief Set set of word break characters. + * + * This setting influences word based cursor movement and line editing capabilities. + * + * \param wordBreakers - 7-bit ASCII set of word breaking characters. + */ + void set_word_break_characters( char const* wordBreakers ); + + /*! \brief How many completions should trigger pagination. + */ + void set_completion_count_cutoff( int count ); + + /*! \brief Set maximum number of displayed hint rows. + */ + void set_max_hint_rows( int count ); + + /*! \brief Set a delay before hint are shown after user stopped typing.. + * + * \param milliseconds - a number of milliseconds to wait before showing hints. + */ + void set_hint_delay( int milliseconds ); + + /*! \brief Set tab completion behavior. + * + * \param val - use double tab to invoke completions. + */ + void set_double_tab_completion( bool val ); + + /*! \brief Set tab completion behavior. + * + * \param val - invoke completion even if user input is empty. + */ + void set_complete_on_empty( bool val ); + + /*! \brief Set tab completion behavior. + * + * \param val - beep if completion is ambiguous. + */ + void set_beep_on_ambiguous_completion( bool val ); + + /*! \brief Set complete next/complete previous behavior. + * + * COMPLETE_NEXT/COMPLETE_PREVIOUS actions have two modes of operations, + * in case when a partial completion is possible complete only partial part (`false` setting) + * or complete first proposed completion fully (`true` setting). + * The default is to complete fully (a `true` setting - complete immediately). + * + * \param val - complete immediately. + */ + void set_immediate_completion( bool val ); + + /*! \brief Set history duplicate entries behaviour. + * + * \param val - should history contain only unique entries? + */ + void set_unique_history( bool val ); + + /*! \brief Disable output coloring. + * + * \param val - if set to non-zero disable output colors. + */ + void set_no_color( bool val ); + + /*! \brief Set maximum number of entries in history list. + */ + void set_max_history_size( int len ); + void clear_screen( void ); + int install_window_change_handler( void ); + void enable_bracketed_paste( void ); + void disable_bracketed_paste( void ); + +private: + Replxx( Replxx const& ) = delete; + Replxx& operator = ( Replxx const& ) = delete; +}; + +} + +#endif /* HAVE_REPLXX_HXX_INCLUDED */ + |