//===----------------------------------------------------------------------===// // DuckDB // // linenoise.hpp // // //===----------------------------------------------------------------------===// #pragma once #include "duckdb/common/common.hpp" #include "duckdb/common/exception.hpp" #include "terminal.hpp" #include "linenoise.h" #define LINENOISE_MAX_LINE 204800 #define LINENOISE_MAX_HISTORY 104857600 #define LINENOISE_EDITOR namespace duckdb { struct highlightToken; struct AppendBuffer; enum class HistoryScrollDirection : uint8_t { LINENOISE_HISTORY_NEXT, LINENOISE_HISTORY_PREV, LINENOISE_HISTORY_START, LINENOISE_HISTORY_END }; enum class Capitalization : uint8_t { CAPITALIZE, LOWERCASE, UPPERCASE }; struct searchMatch { size_t history_index; size_t match_start; size_t match_end; }; struct Completion { string completion; idx_t cursor_pos; }; struct TabCompletion { vector completions; }; class Linenoise { public: Linenoise(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt); public: int Edit(); static void SetCompletionCallback(linenoiseCompletionCallback *fn); static void SetHintsCallback(linenoiseHintsCallback *fn); static void SetFreeHintsCallback(linenoiseFreeHintsCallback *fn); static linenoiseHintsCallback *HintsCallback(); static linenoiseFreeHintsCallback *FreeHintsCallback(); static void SetPrompt(const char *continuation, const char *continuationSelected); static size_t ComputeRenderWidth(const char *buf, size_t len); static int GetRenderPosition(const char *buf, size_t len, int max_width, int *n); static int ParseOption(const char **azArg, int nArg, const char **out_error); int GetPromptWidth() const; void RefreshLine(); int CompleteLine(EscapeSequence ¤t_sequence); void InsertCharacter(char c); int EditInsert(char c); int EditInsertMulti(const char *c); void EditMoveLeft(); void EditMoveRight(); void EditMoveWordLeft(); void EditMoveWordRight(); bool EditMoveRowUp(); bool EditMoveRowDown(); void EditMoveHome(); void EditMoveEnd(); void EditMoveStartOfLine(); void EditMoveEndOfLine(); void EditHistoryNext(HistoryScrollDirection dir); void EditHistorySetIndex(idx_t index); void EditDelete(); void EditBackspace(); void EditDeletePrevWord(); void EditDeleteNextWord(); void EditDeleteAll(); void EditCapitalizeNextWord(Capitalization capitalization); void EditRemoveSpaces(); void EditSwapCharacter(); void EditSwapWord(); void StartSearch(); void CancelSearch(); char AcceptSearch(char nextCommand); void PerformSearch(); void SearchPrev(); void SearchNext(); #ifdef LINENOISE_EDITOR bool EditBufferWithEditor(const char *editor); bool EditFileWithEditor(const string &file_name, const char *editor); #endif char Search(char c); void RefreshMultiLine(); void RefreshSingleLine() const; void RefreshSearch(); void RefreshShowHints(AppendBuffer &append_buffer, int plen) const; size_t PrevChar() const; size_t NextChar() const; void NextPosition(const char *buf, size_t len, size_t &cpos, int &rows, int &cols, int plen) const; void PositionToColAndRow(size_t target_pos, int &out_row, int &out_col, int &rows, int &cols) const; size_t ColAndRowToPosition(int target_row, int target_col) const; string AddContinuationMarkers(const char *buf, size_t len, int plen, int cursor_row, vector &tokens) const; void AddErrorHighlighting(idx_t render_start, idx_t render_end, vector &tokens) const; bool AddCompletionMarker(const char *buf, idx_t len, string &result_buffer, vector &tokens) const; static bool IsNewline(char c); static bool IsWordBoundary(char c); static bool AllWhitespace(const char *z); static bool IsSpace(char c); TabCompletion TabComplete() const; static void EnableCompletionRendering(); static void DisableCompletionRendering(); static void EnableErrorRendering(); static void DisableErrorRendering(); public: static void LogTokens(const vector &tokens); #ifdef LINENOISE_LOGGING // Logging template static void Log(const string &msg, Args... params) { std::vector values; LogMessageRecursive(msg, values, params...); } static void LogMessageRecursive(const string &msg, std::vector &values); template static void LogMessageRecursive(const string &msg, std::vector &values, T param, Args... params) { values.push_back(ExceptionFormatValue::CreateFormatValue(param)); LogMessageRecursive(msg, values, params...); } #else template static void Log(const string &msg, Args... params) { // nop } #endif public: int ifd; /* Terminal stdin file descriptor. */ int ofd; /* Terminal stdout file descriptor. */ char *buf; /* Edited line buffer. */ size_t buflen; /* Edited line buffer size. */ const char *prompt; /* Prompt to display. */ size_t plen; /* Prompt length. */ size_t pos; /* Current cursor position. */ size_t old_cursor_rows; /* Previous refresh cursor position. */ size_t len; /* Current edited line length. */ size_t y_scroll; /* The y scroll position (multiline mode) */ TerminalSize ws; /* Terminal size */ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ idx_t history_index; /* The history index we are currently editing. */ bool clear_screen; /* Whether we are clearing the screen */ bool continuation_markers; /* Whether or not to render continuation markers */ bool search; /* Whether or not we are searching our history */ bool render; /* Whether or not to re-render */ bool has_more_data; /* Whether or not there is more data available in the buffer (copy+paste)*/ bool insert; /* Whether or not the last action was inserting a new character */ std::string search_buf; //! The search buffer std::vector search_matches; //! The set of search matches in our history size_t search_index; //! The current match index }; } // namespace duckdb