mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-19 14:47:49 -04:00
repl: update replxx and some configuration for bracketed paste (#2784)
This commit is contained in:
parent
4643129948
commit
84cd1a5c18
|
@ -150,6 +150,9 @@ void Wrapper::init_settings() {
|
|||
// NOTE - a nice popular project that uses replxx
|
||||
// - https://github.com/ClickHouse/ClickHouse/blob/master/base/base/ReplxxLineReader.cpp#L366
|
||||
repl.set_word_break_characters(" \t");
|
||||
repl.set_complete_on_empty(false);
|
||||
repl.set_indent_multiline(false);
|
||||
repl.enable_bracketed_paste();
|
||||
// Setup default keybinds
|
||||
for (const auto& bind : repl_config.keybinds) {
|
||||
char32_t code;
|
||||
|
@ -168,8 +171,6 @@ void Wrapper::init_settings() {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO - command to print out keybinds
|
||||
|
||||
void Wrapper::reload_startup_file() {
|
||||
startup_file = load_user_startup_file(username, repl_config.game_version);
|
||||
}
|
||||
|
|
38
third-party/replxx/.github/workflows/ci.yml
generated
vendored
Normal file
38
third-party/replxx/.github/workflows/ci.yml
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
# This is a basic workflow to help you get started with Actions
|
||||
|
||||
name: CI
|
||||
|
||||
# Controls when the workflow will run
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the master branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Install required software
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++ cmake python3-pexpect
|
||||
|
||||
# Runs a single command using the runners shell
|
||||
- name: Build the code
|
||||
run: ./build-all.sh
|
||||
|
||||
- name: Run regression tests
|
||||
run: env SKIP=8bit_encoding ./tests.py
|
||||
|
5
third-party/replxx/.gitignore
generated
vendored
5
third-party/replxx/.gitignore
generated
vendored
|
@ -8,7 +8,8 @@ example
|
|||
linenoise_example
|
||||
libreplxx.a
|
||||
*.dSYM
|
||||
history.txt
|
||||
replxx_history.txt
|
||||
replxx_history_alt.txt
|
||||
*.o
|
||||
*~
|
||||
.vs
|
||||
.vs
|
||||
|
|
5
third-party/replxx/CMakeLists.txt
generated
vendored
5
third-party/replxx/CMakeLists.txt
generated
vendored
|
@ -50,7 +50,7 @@ set(REPLXX_CONTACT "amok@codestation.org")
|
|||
set(is-clang $<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>)
|
||||
set(is-msvc $<CXX_COMPILER_ID:MSVC>)
|
||||
set(is-gnu $<CXX_COMPILER_ID:GNU>)
|
||||
set(compiler-id-clang-or-gnu $<AND:$<OR:${is-clang},${is-gnu}>,$<NOT:${is-msvc}>>)
|
||||
set(compiler-id-clang-or-gnu $<OR:${is-clang},${is-gnu}>)
|
||||
|
||||
set(coverage-config $<AND:$<CONFIG:Coverage>,$<OR:${is-gnu},${is-clang}>>)
|
||||
|
||||
|
@ -97,6 +97,7 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
|||
target_link_options(
|
||||
replxx
|
||||
PRIVATE
|
||||
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:GNU>>:-g -ggdb -g3 -ggdb3>
|
||||
$<${coverage-config}:--coverage>
|
||||
$<${is-msvc}:/ignore:4099>
|
||||
)
|
||||
|
@ -182,6 +183,8 @@ if (REPLXX_BUILD_EXAMPLES)
|
|||
)
|
||||
target_compile_definitions(replxx-example-cxx-api PRIVATE REPLXX_STATIC $<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS=1>)
|
||||
target_compile_definitions(replxx-example-c-api PRIVATE REPLXX_STATIC $<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS=1>)
|
||||
target_link_options(replxx-example-cxx-api PRIVATE $<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:GNU>>:-g -ggdb -g3 -ggdb3>)
|
||||
target_link_options(replxx-example-c-api PRIVATE $<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:GNU>>:-g -ggdb -g3 -ggdb3>)
|
||||
target_link_libraries(replxx-example-cxx-api PRIVATE replxx::replxx)
|
||||
target_link_libraries(
|
||||
replxx-example-c-api
|
||||
|
|
18
third-party/replxx/README.md
generated
vendored
18
third-party/replxx/README.md
generated
vendored
|
@ -1,8 +1,8 @@
|
|||
# Read Evaluate Print Loop ++
|
||||
|
||||
![demo](https://drive.google.com/uc?export=download&id=0B53g2Y3z7rWNT2dCRGVVNldaRnc)
|
||||
![demo](https://codestation.org/download/replxx.gif)
|
||||
|
||||
[![Build Status](https://travis-ci.org/AmokHuginnsson/replxx.svg?branch=master)](https://travis-ci.org/AmokHuginnsson/replxx)
|
||||
![Build Status](https://github.com/AmokHuginnsson/replxx/actions/workflows/ci.yml/badge.svg)
|
||||
|
||||
A small, portable GNU readline replacement for Linux, Windows and
|
||||
MacOS which is capable of handling UTF-8 characters. Unlike GNU
|
||||
|
@ -30,13 +30,6 @@ programs.
|
|||
* UTF8 aware
|
||||
* support for Linux, MacOS and Windows
|
||||
|
||||
It deviates from Salvatore's original goal to have a minimal readline
|
||||
replacement for the sake of supporting UTF8 and Windows. It deviates
|
||||
from 10gen Inc.'s goal to create a C++ interface to linenoise. This
|
||||
library uses C++ internally, but to the user it provides a pure C
|
||||
interface that is compatible with the original linenoise API.
|
||||
C interface.
|
||||
|
||||
## Requirements
|
||||
|
||||
To build this library, you will need a C++11-enabled compiler and
|
||||
|
@ -110,10 +103,3 @@ cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_BUILD_TYPE=Release ..
|
|||
|
||||
Please test it everywhere you can and report back!
|
||||
|
||||
## Let's push this forward!
|
||||
|
||||
Patches should be provided in the respect of linenoise sensibility for
|
||||
small and easy to understand code that and the license
|
||||
restrictions. Extensions must be submitted under a BSD license-style.
|
||||
A contributor license is required for contributions.
|
||||
|
||||
|
|
6
third-party/replxx/examples/c-api.c
generated
vendored
6
third-party/replxx/examples/c-api.c
generated
vendored
|
@ -143,6 +143,7 @@ int main( int argc, char** argv ) {
|
|||
int installCompletionCallback = 1;
|
||||
int installHighlighterCallback = 1;
|
||||
int installHintsCallback = 1;
|
||||
int indentMultiline = 0;
|
||||
while ( argc > 1 ) {
|
||||
-- argc;
|
||||
++ argv;
|
||||
|
@ -160,11 +161,13 @@ int main( int argc, char** argv ) {
|
|||
case 'h': replxx_set_max_hint_rows( replxx, atoi( (*argv) + 1 ) ); break;
|
||||
case 'H': replxx_set_hint_delay( replxx, atoi( (*argv) + 1 ) ); break;
|
||||
case 's': replxx_set_max_history_size( replxx, atoi( (*argv) + 1 ) ); break;
|
||||
case 'i': replxx_set_preload_buffer( replxx, recode( (*argv) + 1 ) ); break;
|
||||
case 'P': replxx_set_preload_buffer( replxx, recode( (*argv) + 1 ) ); break;
|
||||
case 'I': replxx_set_immediate_completion( replxx, (*argv)[1] - '0' ); break;
|
||||
case 'u': replxx_set_unique_history( replxx, (*argv)[1] - '0' ); break;
|
||||
case 'w': replxx_set_word_break_characters( replxx, (*argv) + 1 ); break;
|
||||
case 'm': replxx_set_no_color( replxx, (*argv)[1] - '0' ); break;
|
||||
case 'i': replxx_set_ignore_case( replxx, (*argv)[1] - '0' ); break;
|
||||
case 'n': indentMultiline = (*argv)[1] - '0'; break;
|
||||
case 'B': replxx_enable_bracketed_paste( replxx ); break;
|
||||
case 'p': prompt = recode( (*argv) + 1 ); break;
|
||||
case 'q': quiet = atoi( (*argv) + 1 ); break;
|
||||
|
@ -177,6 +180,7 @@ int main( int argc, char** argv ) {
|
|||
|
||||
}
|
||||
|
||||
replxx_set_indent_multiline( replxx, indentMultiline );
|
||||
const char* file = "./replxx_history.txt";
|
||||
|
||||
replxx_history_load( replxx, file );
|
||||
|
|
317
third-party/replxx/examples/cxx-api.cxx
generated
vendored
317
third-party/replxx/examples/cxx-api.cxx
generated
vendored
|
@ -1,12 +1,14 @@
|
|||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <cerrno>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
|
@ -14,20 +16,27 @@
|
|||
#include "util.h"
|
||||
|
||||
using Replxx = replxx::Replxx;
|
||||
using namespace replxx::color;
|
||||
|
||||
class Tick {
|
||||
typedef std::vector<char32_t> keys_t;
|
||||
std::thread _thread;
|
||||
int _tick;
|
||||
int _promptState;
|
||||
bool _alive;
|
||||
keys_t _keys;
|
||||
bool _tickMessages;
|
||||
bool _promptFan;
|
||||
Replxx& _replxx;
|
||||
public:
|
||||
Tick( Replxx& replxx_, std::string const& keys_ = {} )
|
||||
Tick( Replxx& replxx_, std::string const& keys_, bool tickMessages_, bool promptFan_ )
|
||||
: _thread()
|
||||
, _tick( 0 )
|
||||
, _promptState( 0 )
|
||||
, _alive( false )
|
||||
, _keys( keys_.begin(), keys_.end() )
|
||||
, _tickMessages( tickMessages_ )
|
||||
, _promptFan( promptFan_ )
|
||||
, _replxx( replxx_ ) {
|
||||
}
|
||||
void start() {
|
||||
|
@ -40,26 +49,56 @@ public:
|
|||
}
|
||||
void run() {
|
||||
std::string s;
|
||||
static char const PROMPT_STATES[] = "-\\|/";
|
||||
while ( _alive ) {
|
||||
if ( _keys.empty() ) {
|
||||
if ( _tickMessages ) {
|
||||
_replxx.print( "%d\n", _tick );
|
||||
} else if ( _tick < static_cast<int>( _keys.size() ) ) {
|
||||
}
|
||||
if ( _tick < static_cast<int>( _keys.size() ) ) {
|
||||
_replxx.emulate_key_press( _keys[_tick] );
|
||||
} else {
|
||||
}
|
||||
if ( ! _tickMessages && ! _promptFan && ( _tick >= static_cast<int>( _keys.size() ) ) ) {
|
||||
break;
|
||||
}
|
||||
if ( _promptFan ) {
|
||||
for ( int i( 0 ); i < 4; ++ i ) {
|
||||
char prompt[] = "\x1b[1;32mreplxx\x1b[0m[ ]> ";
|
||||
prompt[18] = PROMPT_STATES[_promptState % 4];
|
||||
++ _promptState;
|
||||
_replxx.set_prompt( prompt );
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) );
|
||||
}
|
||||
} else {
|
||||
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
|
||||
}
|
||||
++ _tick;
|
||||
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// prototypes
|
||||
Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& user_data);
|
||||
Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& user_data);
|
||||
void hook_color(std::string const& str, Replxx::colors_t& colors, std::vector<std::pair<std::string, Replxx::Color>> const& user_data);
|
||||
Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& user_data, bool);
|
||||
Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& user_data, bool);
|
||||
typedef std::vector<std::pair<std::string, Replxx::Color>> syntax_highlight_t;
|
||||
typedef std::unordered_map<std::string, Replxx::Color> keyword_highlight_t;
|
||||
void hook_color( std::string const& str, Replxx::colors_t& colors, syntax_highlight_t const&, keyword_highlight_t const& );
|
||||
void hook_modify( std::string& line, int& cursorPosition, Replxx* );
|
||||
|
||||
Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& examples) {
|
||||
bool eq( std::string const& l, std::string const& r, int s, bool ic ) {
|
||||
if ( static_cast<int>( l.length() ) < s ) {
|
||||
return false;
|
||||
}
|
||||
if ( static_cast<int>( r.length() ) < s ) {
|
||||
return false;
|
||||
}
|
||||
bool same( true );
|
||||
for ( int i( 0 ); same && ( i < s ); ++ i ) {
|
||||
same = ( ic && ( towlower( l[i] ) == towlower( r[i] ) ) ) || ( l[i] == r[i] );
|
||||
}
|
||||
return same;
|
||||
}
|
||||
|
||||
Replxx::completions_t hook_completion(std::string const& context, int& contextLen, std::vector<std::string> const& examples, bool ignoreCase) {
|
||||
Replxx::completions_t completions;
|
||||
int utf8ContextLen( context_len( context.c_str() ) );
|
||||
int prefixLen( static_cast<int>( context.length() ) - utf8ContextLen );
|
||||
|
@ -74,7 +113,8 @@ Replxx::completions_t hook_completion(std::string const& context, int& contextLe
|
|||
completions.push_back( "π" );
|
||||
} else {
|
||||
for (auto const& e : examples) {
|
||||
if (e.compare(0, prefix.size(), prefix) == 0) {
|
||||
bool lowerCasePrefix( std::none_of( prefix.begin(), prefix.end(), iswupper ) );
|
||||
if ( eq( e, prefix, static_cast<int>( prefix.size() ), ignoreCase && lowerCasePrefix ) ) {
|
||||
Replxx::Color c( Replxx::Color::DEFAULT );
|
||||
if ( e.find( "brightred" ) != std::string::npos ) {
|
||||
c = Replxx::Color::BRIGHTRED;
|
||||
|
@ -89,7 +129,7 @@ Replxx::completions_t hook_completion(std::string const& context, int& contextLe
|
|||
return completions;
|
||||
}
|
||||
|
||||
Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& examples) {
|
||||
Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::Color& color, std::vector<std::string> const& examples, bool ignoreCase) {
|
||||
Replxx::hints_t hints;
|
||||
|
||||
// only show hint if prefix is at least 'n' chars long
|
||||
|
@ -101,8 +141,9 @@ Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::C
|
|||
std::string prefix { context.substr(prefixLen) };
|
||||
|
||||
if (prefix.size() >= 2 || (! prefix.empty() && prefix.at(0) == '.')) {
|
||||
bool lowerCasePrefix( std::none_of( prefix.begin(), prefix.end(), iswupper ) );
|
||||
for (auto const& e : examples) {
|
||||
if (e.compare(0, prefix.size(), prefix) == 0) {
|
||||
if ( eq( e, prefix, prefix.size(), ignoreCase && lowerCasePrefix ) ) {
|
||||
hints.emplace_back(e.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +157,11 @@ Replxx::hints_t hook_hint(std::string const& context, int& contextLen, Replxx::C
|
|||
return hints;
|
||||
}
|
||||
|
||||
void hook_color(std::string const& context, Replxx::colors_t& colors, std::vector<std::pair<std::string, Replxx::Color>> const& regex_color) {
|
||||
inline bool is_kw( char ch ) {
|
||||
return isalnum( ch ) || ( ch == '_' );
|
||||
}
|
||||
|
||||
void hook_color( std::string const& context, Replxx::colors_t& colors, syntax_highlight_t const& regex_color, keyword_highlight_t const& word_color ) {
|
||||
// highlight matching regex sequences
|
||||
for (auto const& e : regex_color) {
|
||||
size_t pos {0};
|
||||
|
@ -137,6 +182,69 @@ void hook_color(std::string const& context, Replxx::colors_t& colors, std::vecto
|
|||
str = match.suffix();
|
||||
}
|
||||
}
|
||||
bool inWord( false );
|
||||
int wordStart( 0 );
|
||||
int wordEnd( 0 );
|
||||
int colorOffset( 0 );
|
||||
auto dohl = [&](int i) {
|
||||
inWord = false;
|
||||
std::string intermission( context.substr( wordEnd, wordStart - wordEnd ) );
|
||||
colorOffset += utf8str_codepoint_len( intermission.c_str(), intermission.length() );
|
||||
int wordLen( i - wordStart );
|
||||
std::string keyword( context.substr( wordStart, wordLen ) );
|
||||
bool bold( false );
|
||||
if ( keyword.substr( 0, 5 ) == "bold_" ) {
|
||||
keyword = keyword.substr( 5 );
|
||||
bold = true;
|
||||
}
|
||||
bool underline( false );
|
||||
if ( keyword.substr( 0, 10 ) == "underline_" ) {
|
||||
keyword = keyword.substr( 10 );
|
||||
underline = true;
|
||||
}
|
||||
keyword_highlight_t::const_iterator it( word_color.find( keyword ) );
|
||||
Replxx::Color color = Replxx::Color::DEFAULT;
|
||||
if ( it != word_color.end() ) {
|
||||
color = it->second;
|
||||
}
|
||||
if ( bold ) {
|
||||
color = replxx::color::bold( color );
|
||||
}
|
||||
if ( underline ) {
|
||||
color = replxx::color::underline( color );
|
||||
}
|
||||
for ( int k( 0 ); k < wordLen; ++ k ) {
|
||||
Replxx::Color& c( colors.at( colorOffset + k ) );
|
||||
if ( color != Replxx::Color::DEFAULT ) {
|
||||
c = color;
|
||||
}
|
||||
}
|
||||
colorOffset += wordLen;
|
||||
wordEnd = i;
|
||||
};
|
||||
for ( int i( 0 ); i < static_cast<int>( context.length() ); ++ i ) {
|
||||
if ( !inWord ) {
|
||||
if ( is_kw( context[i] ) ) {
|
||||
inWord = true;
|
||||
wordStart = i;
|
||||
}
|
||||
} else if ( inWord && !is_kw( context[i] ) ) {
|
||||
dohl(i);
|
||||
}
|
||||
if ( ( context[i] != '_' ) && ispunct( context[i] ) ) {
|
||||
wordStart = i;
|
||||
dohl( i + 1 );
|
||||
}
|
||||
}
|
||||
if ( inWord ) {
|
||||
dohl(context.length());
|
||||
}
|
||||
}
|
||||
|
||||
void hook_modify( std::string& currentInput_, int&, Replxx* rx ) {
|
||||
char prompt[64];
|
||||
snprintf( prompt, 64, "\x1b[1;32mreplxx\x1b[0m[%lu]> ", currentInput_.length() );
|
||||
rx->set_prompt( prompt );
|
||||
}
|
||||
|
||||
Replxx::ACTION_RESULT message( Replxx& replxx, std::string s, char32_t ) {
|
||||
|
@ -154,31 +262,33 @@ int main( int argc_, char** argv_ ) {
|
|||
"color_black", "color_red", "color_green", "color_brown", "color_blue",
|
||||
"color_magenta", "color_cyan", "color_lightgray", "color_gray",
|
||||
"color_brightred", "color_brightgreen", "color_yellow", "color_brightblue",
|
||||
"color_brightmagenta", "color_brightcyan", "color_white", "color_normal",
|
||||
"color_brightmagenta", "color_brightcyan", "color_white",
|
||||
"determinANT", "determiNATION", "deterMINE", "deteRMINISM", "detERMINISTIC", "deTERMINED",
|
||||
"star", "star_galaxy_cluser_supercluster_observable_universe",
|
||||
};
|
||||
|
||||
// highlight specific words
|
||||
// a regex string, and a color
|
||||
// the order matters, the last match will take precedence
|
||||
using cl = Replxx::Color;
|
||||
std::vector<std::pair<std::string, cl>> regex_color {
|
||||
keyword_highlight_t word_color {
|
||||
// single chars
|
||||
{"\\`", cl::BRIGHTCYAN},
|
||||
{"\\'", cl::BRIGHTBLUE},
|
||||
{"\\\"", cl::BRIGHTBLUE},
|
||||
{"\\-", cl::BRIGHTBLUE},
|
||||
{"\\+", cl::BRIGHTBLUE},
|
||||
{"\\=", cl::BRIGHTBLUE},
|
||||
{"\\/", cl::BRIGHTBLUE},
|
||||
{"\\*", cl::BRIGHTBLUE},
|
||||
{"\\^", cl::BRIGHTBLUE},
|
||||
{"\\.", cl::BRIGHTMAGENTA},
|
||||
{"\\(", cl::BRIGHTMAGENTA},
|
||||
{"\\)", cl::BRIGHTMAGENTA},
|
||||
{"\\[", cl::BRIGHTMAGENTA},
|
||||
{"\\]", cl::BRIGHTMAGENTA},
|
||||
{"\\{", cl::BRIGHTMAGENTA},
|
||||
{"\\}", cl::BRIGHTMAGENTA},
|
||||
{"`", cl::BRIGHTCYAN},
|
||||
{"'", cl::BRIGHTBLUE},
|
||||
{"\"", cl::BRIGHTBLUE},
|
||||
{"-", cl::BRIGHTBLUE},
|
||||
{"+", cl::BRIGHTBLUE},
|
||||
{"=", cl::BRIGHTBLUE},
|
||||
{"/", cl::BRIGHTBLUE},
|
||||
{"*", cl::BRIGHTBLUE},
|
||||
{"^", cl::BRIGHTBLUE},
|
||||
{".", cl::BRIGHTMAGENTA},
|
||||
{"(", cl::BRIGHTMAGENTA},
|
||||
{")", cl::BRIGHTMAGENTA},
|
||||
{"[", cl::BRIGHTMAGENTA},
|
||||
{"]", cl::BRIGHTMAGENTA},
|
||||
{"{", cl::BRIGHTMAGENTA},
|
||||
{"}", cl::BRIGHTMAGENTA},
|
||||
|
||||
// color keywords
|
||||
{"color_black", cl::BLACK},
|
||||
|
@ -197,16 +307,16 @@ int main( int argc_, char** argv_ ) {
|
|||
{"color_brightmagenta", cl::BRIGHTMAGENTA},
|
||||
{"color_brightcyan", cl::BRIGHTCYAN},
|
||||
{"color_white", cl::WHITE},
|
||||
{"color_normal", cl::NORMAL},
|
||||
|
||||
// commands
|
||||
{"\\.help", cl::BRIGHTMAGENTA},
|
||||
{"\\.history", cl::BRIGHTMAGENTA},
|
||||
{"\\.quit", cl::BRIGHTMAGENTA},
|
||||
{"\\.exit", cl::BRIGHTMAGENTA},
|
||||
{"\\.clear", cl::BRIGHTMAGENTA},
|
||||
{"\\.prompt", cl::BRIGHTMAGENTA},
|
||||
|
||||
{"help", cl::BRIGHTMAGENTA},
|
||||
{"history", cl::BRIGHTMAGENTA},
|
||||
{"quit", cl::BRIGHTMAGENTA},
|
||||
{"exit", cl::BRIGHTMAGENTA},
|
||||
{"clear", cl::BRIGHTMAGENTA},
|
||||
{"prompt", cl::BRIGHTMAGENTA},
|
||||
};
|
||||
syntax_highlight_t regex_color {
|
||||
// numbers
|
||||
{"[\\-|+]{0,1}[0-9]+", cl::YELLOW}, // integers
|
||||
{"[\\-|+]{0,1}[0-9]*\\.[0-9]+", cl::YELLOW}, // decimals
|
||||
|
@ -216,17 +326,89 @@ int main( int argc_, char** argv_ ) {
|
|||
{"\".*?\"", cl::BRIGHTGREEN}, // double quotes
|
||||
{"\'.*?\'", cl::BRIGHTGREEN}, // single quotes
|
||||
};
|
||||
static int const MAX_LABEL_NAME( 32 );
|
||||
char label[MAX_LABEL_NAME];
|
||||
for ( int r( 0 ); r < 6; ++ r ) {
|
||||
for ( int g( 0 ); g < 6; ++ g ) {
|
||||
for ( int b( 0 ); b < 6; ++ b ) {
|
||||
snprintf( label, MAX_LABEL_NAME, "rgb%d%d%d", r, g, b );
|
||||
word_color.insert( std::make_pair( label, replxx::color::rgb666( r, g, b ) ) );
|
||||
for ( int br( 0 ); br < 6; ++ br ) {
|
||||
for ( int bg( 0 ); bg < 6; ++ bg ) {
|
||||
for ( int bb( 0 ); bb < 6; ++ bb ) {
|
||||
snprintf( label, MAX_LABEL_NAME, "fg%d%d%dbg%d%d%d", r, g, b, br, bg, bb );
|
||||
word_color.insert(
|
||||
std::make_pair(
|
||||
label,
|
||||
rgb666( r, g, b ) | replxx::color::bg( rgb666( br, bg, bb ) )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( int gs( 0 ); gs < 24; ++ gs ) {
|
||||
snprintf( label, MAX_LABEL_NAME, "gs%d", gs );
|
||||
word_color.insert( std::make_pair( label, grayscale( gs ) ) );
|
||||
for ( int bgs( 0 ); bgs < 24; ++ bgs ) {
|
||||
snprintf( label, MAX_LABEL_NAME, "gs%dgs%d", gs, bgs );
|
||||
word_color.insert( std::make_pair( label, grayscale( gs ) | bg( grayscale( bgs ) ) ) );
|
||||
}
|
||||
}
|
||||
Replxx::Color colorCodes[] = {
|
||||
Replxx::Color::BLACK, Replxx::Color::RED, Replxx::Color::GREEN, Replxx::Color::BROWN, Replxx::Color::BLUE,
|
||||
Replxx::Color::CYAN, Replxx::Color::MAGENTA, Replxx::Color::LIGHTGRAY, Replxx::Color::GRAY, Replxx::Color::BRIGHTRED,
|
||||
Replxx::Color::BRIGHTGREEN, Replxx::Color::YELLOW, Replxx::Color::BRIGHTBLUE, Replxx::Color::BRIGHTCYAN,
|
||||
Replxx::Color::BRIGHTMAGENTA, Replxx::Color::WHITE
|
||||
};
|
||||
for ( Replxx::Color bg : colorCodes ) {
|
||||
for ( Replxx::Color fg : colorCodes ) {
|
||||
snprintf( label, MAX_LABEL_NAME, "c_%d_%d", static_cast<int>( fg ), static_cast<int>( bg ) );
|
||||
word_color.insert( std::make_pair( label, fg | replxx::color::bg( bg ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool tickMessages( false );
|
||||
bool promptFan( false );
|
||||
bool promptInCallback( false );
|
||||
bool indentMultiline( false );
|
||||
bool bracketedPaste( false );
|
||||
bool ignoreCase( false );
|
||||
std::string keys;
|
||||
std::string prompt;
|
||||
int hintDelay( 0 );
|
||||
while ( argc_ > 1 ) {
|
||||
-- argc_;
|
||||
++ argv_;
|
||||
switch ( (*argv_)[0] ) {
|
||||
case ( 'm' ): tickMessages = true; break;
|
||||
case ( 'F' ): promptFan = true; break;
|
||||
case ( 'P' ): promptInCallback = true; break;
|
||||
case ( 'I' ): indentMultiline = true; break;
|
||||
case ( 'i' ): ignoreCase = true; break;
|
||||
case ( 'k' ): keys = (*argv_) + 1; break;
|
||||
case ( 'd' ): hintDelay = std::stoi( (*argv_) + 1 ); break;
|
||||
case ( 'h' ): examples.push_back( (*argv_) + 1 ); break;
|
||||
case ( 'p' ): prompt = (*argv_) + 1; break;
|
||||
case ( 'B' ): bracketedPaste = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
// init the repl
|
||||
Replxx rx;
|
||||
Tick tick( rx, argc_ > 1 ? argv_[1] : "" );
|
||||
Tick tick( rx, keys, tickMessages, promptFan );
|
||||
rx.install_window_change_handler();
|
||||
|
||||
// the path to the history file
|
||||
std::string history_file {"./replxx_history.txt"};
|
||||
std::string history_file_path {"./replxx_history.txt"};
|
||||
|
||||
// load the history file if it exists
|
||||
rx.history_load(history_file);
|
||||
/* scope for ifstream object for auto-close */ {
|
||||
std::ifstream history_file( history_file_path.c_str() );
|
||||
rx.history_load( history_file );
|
||||
}
|
||||
|
||||
// set the max history size
|
||||
rx.set_max_history_size(128);
|
||||
|
@ -236,25 +418,36 @@ int main( int argc_, char** argv_ ) {
|
|||
|
||||
// set the callbacks
|
||||
using namespace std::placeholders;
|
||||
rx.set_completion_callback( std::bind( &hook_completion, _1, _2, cref( examples ) ) );
|
||||
rx.set_highlighter_callback( std::bind( &hook_color, _1, _2, cref( regex_color ) ) );
|
||||
rx.set_hint_callback( std::bind( &hook_hint, _1, _2, _3, cref( examples ) ) );
|
||||
rx.set_completion_callback( std::bind( &hook_completion, _1, _2, cref( examples ), ignoreCase ) );
|
||||
rx.set_highlighter_callback( std::bind( &hook_color, _1, _2, cref( regex_color ), cref( word_color ) ) );
|
||||
rx.set_hint_callback( std::bind( &hook_hint, _1, _2, _3, cref( examples ), ignoreCase ) );
|
||||
if ( promptInCallback ) {
|
||||
rx.set_modify_callback( std::bind( &hook_modify, _1, _2, &rx ) );
|
||||
}
|
||||
|
||||
// other api calls
|
||||
rx.set_word_break_characters( " \t.,-%!;:=*~^'\"/?<>|[](){}" );
|
||||
rx.set_word_break_characters( " \n\t.,-%!;:=*~^'\"/?<>|[](){}" );
|
||||
rx.set_completion_count_cutoff( 128 );
|
||||
rx.set_hint_delay( hintDelay );
|
||||
rx.set_double_tab_completion( false );
|
||||
rx.set_complete_on_empty( true );
|
||||
rx.set_beep_on_ambiguous_completion( false );
|
||||
rx.set_no_color( false );
|
||||
rx.set_indent_multiline( indentMultiline );
|
||||
if ( bracketedPaste ) {
|
||||
rx.enable_bracketed_paste();
|
||||
}
|
||||
rx.set_ignore_case( ignoreCase );
|
||||
|
||||
// showcase key bindings
|
||||
rx.bind_key_internal( Replxx::KEY::BACKSPACE, "delete_character_left_of_cursor" );
|
||||
rx.bind_key_internal( Replxx::KEY::DELETE, "delete_character_under_cursor" );
|
||||
rx.bind_key_internal( Replxx::KEY::LEFT, "move_cursor_left" );
|
||||
rx.bind_key_internal( Replxx::KEY::RIGHT, "move_cursor_right" );
|
||||
rx.bind_key_internal( Replxx::KEY::UP, "history_previous" );
|
||||
rx.bind_key_internal( Replxx::KEY::DOWN, "history_next" );
|
||||
rx.bind_key_internal( Replxx::KEY::UP, "line_previous" );
|
||||
rx.bind_key_internal( Replxx::KEY::DOWN, "line_next" );
|
||||
rx.bind_key_internal( Replxx::KEY::meta( Replxx::KEY::UP ), "history_previous" );
|
||||
rx.bind_key_internal( Replxx::KEY::meta( Replxx::KEY::DOWN ), "history_next" );
|
||||
rx.bind_key_internal( Replxx::KEY::PAGE_UP, "history_first" );
|
||||
rx.bind_key_internal( Replxx::KEY::PAGE_DOWN, "history_last" );
|
||||
rx.bind_key_internal( Replxx::KEY::HOME, "move_cursor_to_begining_of_line" );
|
||||
|
@ -335,6 +528,7 @@ int main( int argc_, char** argv_ ) {
|
|||
rx.bind_key( Replxx::KEY::shift( Replxx::KEY::RIGHT ), std::bind( &message, std::ref( rx ), "<S-Right>", _1 ) );
|
||||
rx.bind_key( Replxx::KEY::shift( Replxx::KEY::UP ), std::bind( &message, std::ref( rx ), "<S-Up>", _1 ) );
|
||||
rx.bind_key( Replxx::KEY::shift( Replxx::KEY::DOWN ), std::bind( &message, std::ref( rx ), "<S-Down>", _1 ) );
|
||||
rx.bind_key( Replxx::KEY::meta( '\r' ), std::bind( &message, std::ref( rx ), "<M-Enter>", _1 ) );
|
||||
|
||||
// display initial welcome message
|
||||
std::cout
|
||||
|
@ -344,10 +538,12 @@ int main( int argc_, char** argv_ ) {
|
|||
<< "Type '.quit' or '.exit' to exit\n\n";
|
||||
|
||||
// set the repl prompt
|
||||
std::string prompt {"\x1b[1;32mreplxx\x1b[0m> "};
|
||||
if ( prompt.empty() ) {
|
||||
prompt = "\x1b[1;32mreplxx\x1b[0m> ";
|
||||
}
|
||||
|
||||
// main repl loop
|
||||
if ( argc_ > 1 ) {
|
||||
if ( ! keys.empty() || tickMessages || promptFan ) {
|
||||
tick.start();
|
||||
}
|
||||
for (;;) {
|
||||
|
@ -413,14 +609,15 @@ int main( int argc_, char** argv_ ) {
|
|||
continue;
|
||||
|
||||
} else if (input.compare(0, 6, ".merge") == 0) {
|
||||
history_file = "replxx_history_alt.txt";
|
||||
history_file_path = "replxx_history_alt.txt";
|
||||
|
||||
rx.history_add(input);
|
||||
continue;
|
||||
|
||||
} else if (input.compare(0, 5, ".save") == 0) {
|
||||
history_file = "replxx_history_alt.txt";
|
||||
rx.history_save(history_file);
|
||||
history_file_path = "replxx_history_alt.txt";
|
||||
std::ofstream history_file( history_file_path.c_str() );
|
||||
rx.history_save( history_file );
|
||||
continue;
|
||||
|
||||
} else if (input.compare(0, 6, ".clear") == 0) {
|
||||
|
@ -440,12 +637,18 @@ int main( int argc_, char** argv_ ) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if ( argc_ > 1 ) {
|
||||
if ( ! keys.empty() || tickMessages || promptFan ) {
|
||||
tick.stop();
|
||||
}
|
||||
|
||||
// save the history
|
||||
rx.history_sync(history_file);
|
||||
rx.history_sync( history_file_path );
|
||||
if ( bracketedPaste ) {
|
||||
rx.disable_bracketed_paste();
|
||||
}
|
||||
if ( bracketedPaste || promptInCallback || promptFan ) {
|
||||
std::cout << "\n" << prompt;
|
||||
}
|
||||
|
||||
std::cout << "\nExiting Replxx\n";
|
||||
|
||||
|
|
93
third-party/replxx/include/replxx.h
generated
vendored
93
third-party/replxx/include/replxx.h
generated
vendored
|
@ -81,9 +81,7 @@ typedef enum {
|
|||
REPLXX_COLOR_BRIGHTMAGENTA = 13,
|
||||
REPLXX_COLOR_BRIGHTCYAN = 14,
|
||||
REPLXX_COLOR_WHITE = 15,
|
||||
REPLXX_COLOR_NORMAL = REPLXX_COLOR_LIGHTGRAY,
|
||||
REPLXX_COLOR_DEFAULT = -1,
|
||||
REPLXX_COLOR_ERROR = -2
|
||||
REPLXX_COLOR_DEFAULT = 1u << 16u
|
||||
} ReplxxColor;
|
||||
|
||||
enum { REPLXX_KEY_BASE = 0x0010ffff + 1 };
|
||||
|
@ -136,17 +134,21 @@ enum { REPLXX_KEY_PASTE_FINISH = REPLXX_KEY_PASTE_START + 1 };
|
|||
enum { REPLXX_KEY_BACKSPACE = REPLXX_KEY_CONTROL( 'H' ) };
|
||||
enum { REPLXX_KEY_TAB = REPLXX_KEY_CONTROL( 'I' ) };
|
||||
enum { REPLXX_KEY_ENTER = REPLXX_KEY_CONTROL( 'M' ) };
|
||||
enum { REPLXX_KEY_ABORT = REPLXX_KEY_META( REPLXX_KEY_CONTROL( 'M' ) ) };
|
||||
|
||||
/*! \brief List of built-in actions that act upon user input.
|
||||
*/
|
||||
typedef enum {
|
||||
REPLXX_ACTION_INSERT_CHARACTER,
|
||||
REPLXX_ACTION_NEW_LINE,
|
||||
REPLXX_ACTION_DELETE_CHARACTER_UNDER_CURSOR,
|
||||
REPLXX_ACTION_DELETE_CHARACTER_LEFT_OF_CURSOR,
|
||||
REPLXX_ACTION_KILL_TO_END_OF_LINE,
|
||||
REPLXX_ACTION_KILL_TO_BEGINING_OF_LINE,
|
||||
REPLXX_ACTION_KILL_TO_END_OF_WORD,
|
||||
REPLXX_ACTION_KILL_TO_BEGINING_OF_WORD,
|
||||
REPLXX_ACTION_KILL_TO_END_OF_SUBWORD,
|
||||
REPLXX_ACTION_KILL_TO_BEGINING_OF_SUBWORD,
|
||||
REPLXX_ACTION_KILL_TO_WHITESPACE_ON_LEFT,
|
||||
REPLXX_ACTION_YANK,
|
||||
REPLXX_ACTION_YANK_CYCLE,
|
||||
|
@ -155,19 +157,29 @@ typedef enum {
|
|||
REPLXX_ACTION_MOVE_CURSOR_TO_END_OF_LINE,
|
||||
REPLXX_ACTION_MOVE_CURSOR_ONE_WORD_LEFT,
|
||||
REPLXX_ACTION_MOVE_CURSOR_ONE_WORD_RIGHT,
|
||||
REPLXX_ACTION_MOVE_CURSOR_ONE_SUBWORD_LEFT,
|
||||
REPLXX_ACTION_MOVE_CURSOR_ONE_SUBWORD_RIGHT,
|
||||
REPLXX_ACTION_MOVE_CURSOR_LEFT,
|
||||
REPLXX_ACTION_MOVE_CURSOR_RIGHT,
|
||||
REPLXX_ACTION_HISTORY_NEXT,
|
||||
REPLXX_ACTION_HISTORY_PREVIOUS,
|
||||
REPLXX_ACTION_LINE_NEXT,
|
||||
REPLXX_ACTION_LINE_PREVIOUS,
|
||||
REPLXX_ACTION_HISTORY_MOVE_NEXT,
|
||||
REPLXX_ACTION_HISTORY_MOVE_PREVIOUS,
|
||||
REPLXX_ACTION_HISTORY_FIRST,
|
||||
REPLXX_ACTION_HISTORY_LAST,
|
||||
REPLXX_ACTION_HISTORY_RESTORE,
|
||||
REPLXX_ACTION_HISTORY_RESTORE_CURRENT,
|
||||
REPLXX_ACTION_HISTORY_INCREMENTAL_SEARCH,
|
||||
REPLXX_ACTION_HISTORY_SEEDED_INCREMENTAL_SEARCH,
|
||||
REPLXX_ACTION_HISTORY_COMMON_PREFIX_SEARCH,
|
||||
REPLXX_ACTION_HINT_NEXT,
|
||||
REPLXX_ACTION_HINT_PREVIOUS,
|
||||
REPLXX_ACTION_CAPITALIZE_WORD,
|
||||
REPLXX_ACTION_LOWERCASE_WORD,
|
||||
REPLXX_ACTION_UPPERCASE_WORD,
|
||||
REPLXX_ACTION_CAPITALIZE_SUBWORD,
|
||||
REPLXX_ACTION_LOWERCASE_SUBWORD,
|
||||
REPLXX_ACTION_UPPERCASE_SUBWORD,
|
||||
REPLXX_ACTION_TRANSPOSE_CHARACTERS,
|
||||
REPLXX_ACTION_TOGGLE_OVERWRITE_MODE,
|
||||
#ifndef _WIN32
|
||||
|
@ -381,6 +393,12 @@ REPLXX_IMPEXP void replxx_get_state( Replxx*, ReplxxState* state );
|
|||
*/
|
||||
REPLXX_IMPEXP void replxx_set_state( Replxx*, ReplxxState* state );
|
||||
|
||||
/*! \brief Enable/disable case insensitive history search and completion.
|
||||
*
|
||||
* \param val - if set to non-zero then history search and completion will be case insensitive.
|
||||
*/
|
||||
REPLXX_IMPEXP void replxx_set_ignore_case( Replxx*, int val );
|
||||
|
||||
/*! \brief Print formatted string to standard output.
|
||||
*
|
||||
* This function ensures proper handling of ANSI escape sequences
|
||||
|
@ -400,6 +418,14 @@ REPLXX_IMPEXP int replxx_print( Replxx*, char const* fmt, ... );
|
|||
*/
|
||||
REPLXX_IMPEXP int replxx_write( Replxx*, char const* str, int length );
|
||||
|
||||
/*! \brief Asynchronously change the prompt while replxx_input() call is in efect.
|
||||
*
|
||||
* Can be used to change the prompt from callbacks or other threads.
|
||||
*
|
||||
* \param prompt - The prompt string to change to.
|
||||
*/
|
||||
REPLXX_IMPEXP void replxx_set_prompt( Replxx*, const char* prompt );
|
||||
|
||||
/*! \brief Schedule an emulated key press event.
|
||||
*
|
||||
* \param code - key press code to be emulated.
|
||||
|
@ -428,8 +454,8 @@ REPLXX_IMPEXP void replxx_bind_key( Replxx*, int code, key_press_handler_t handl
|
|||
*
|
||||
* Action names are the same as unique part of names of ReplxxAction 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".
|
||||
* is \e REPLXX_ACTION_LINE_PREVIOUS so action name to be used in this
|
||||
* interface for the same effect is "line_previous".
|
||||
*
|
||||
* \param code - handle this key-press event with following handler.
|
||||
* \param actionName - name of internal action to be invoked on key press.
|
||||
|
@ -505,6 +531,12 @@ REPLXX_IMPEXP void replxx_set_unique_history( Replxx*, int val );
|
|||
*/
|
||||
REPLXX_IMPEXP void replxx_set_no_color( Replxx*, int val );
|
||||
|
||||
/*! \brief Enable/disable (prompt width) indent for multiline entry.
|
||||
*
|
||||
* \param val - if set to non-zero then multiline indent will be enabled.
|
||||
*/
|
||||
REPLXX_IMPEXP void replxx_set_indent_multiline( Replxx*, int val );
|
||||
|
||||
/*! \brief Set maximum number of entries in history list.
|
||||
*/
|
||||
REPLXX_IMPEXP void replxx_set_max_history_size( Replxx*, int len );
|
||||
|
@ -559,6 +591,53 @@ REPLXX_IMPEXP int replxx_install_window_change_handler( Replxx* );
|
|||
REPLXX_IMPEXP void replxx_enable_bracketed_paste( Replxx* );
|
||||
REPLXX_IMPEXP void replxx_disable_bracketed_paste( Replxx* );
|
||||
|
||||
/*! \brief Combine two color definitions to get encompassing color definition.
|
||||
*
|
||||
* To be used only for combining foreground and background colors.
|
||||
*
|
||||
* \param color1 - first input color.
|
||||
* \param color2 - second input color.
|
||||
* \return A new color definition that represent combined input colors.
|
||||
*/
|
||||
ReplxxColor replxx_color_combine( ReplxxColor color1, ReplxxColor color2 );
|
||||
|
||||
/*! \brief Transform foreground color definition into a background color definition.
|
||||
*
|
||||
* \param color - an input foreground color definition.
|
||||
* \return A background color definition that is a transformed input \e color.
|
||||
*/
|
||||
ReplxxColor replxx_color_bg( ReplxxColor color );
|
||||
|
||||
/*! \brief Add `bold` attribute to color definition.
|
||||
*
|
||||
* \param color - an input color definition.
|
||||
* \return A new color definition with bold attribute set.
|
||||
*/
|
||||
ReplxxColor replxx_color_bold( ReplxxColor color );
|
||||
|
||||
/*! \brief Add `underline` attribute to color definition.
|
||||
*
|
||||
* \param color - an input color definition.
|
||||
* \return A new color definition with underline attribute set.
|
||||
*/
|
||||
ReplxxColor replxx_color_underline( ReplxxColor color );
|
||||
|
||||
/*! \brief Create a new grayscale color of given brightness level.
|
||||
*
|
||||
* \param level - a brightness level for new color, must be between 0 (darkest) and 23 (brightest).
|
||||
* \return A new grayscale color of a given brightest \e level.
|
||||
*/
|
||||
ReplxxColor replxx_color_grayscale( int level );
|
||||
|
||||
/*! \brief Create a new color in 6×6×6 RGB color space from base component levels.
|
||||
*
|
||||
* \param red - a red (of RGB) component level, must be 0 and 5.
|
||||
* \param green - a green (of RGB) component level, must be 0 and 5.
|
||||
* \param blue - a blue (of RGB) component level, must be 0 and 5.
|
||||
* \return A new color in 6×6×6 RGB color space.
|
||||
*/
|
||||
ReplxxColor replxx_color_rgb666( int red, int green, int blue );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
117
third-party/replxx/include/replxx.hxx
generated
vendored
117
third-party/replxx/include/replxx.hxx
generated
vendored
|
@ -35,6 +35,7 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
|
||||
/*
|
||||
* For use in Windows DLLs:
|
||||
|
@ -59,6 +60,11 @@ enum { ERROR_BB1CA97EC761FC37101737BA0AA2E7C5 = ERROR };
|
|||
#undef ERROR
|
||||
enum { ERROR = ERROR_BB1CA97EC761FC37101737BA0AA2E7C5 };
|
||||
#endif
|
||||
#ifdef ABORT
|
||||
enum { ABORT_8D12A2CA7E5A64036D7251A3EDA51A38 = ABORT };
|
||||
#undef ABORT
|
||||
enum { ABORT = ABORT_8D12A2CA7E5A64036D7251A3EDA51A38 };
|
||||
#endif
|
||||
#ifdef DELETE
|
||||
enum { DELETE_32F68A60CEF40FAEDBC6AF20298C1A1E = DELETE };
|
||||
#undef DELETE
|
||||
|
@ -69,7 +75,7 @@ namespace replxx {
|
|||
|
||||
class REPLXX_IMPEXP Replxx {
|
||||
public:
|
||||
enum class Color {
|
||||
enum class Color : int {
|
||||
BLACK = 0,
|
||||
RED = 1,
|
||||
GREEN = 2,
|
||||
|
@ -86,9 +92,7 @@ public:
|
|||
BRIGHTMAGENTA = 13,
|
||||
BRIGHTCYAN = 14,
|
||||
WHITE = 15,
|
||||
NORMAL = LIGHTGRAY,
|
||||
DEFAULT = -1,
|
||||
ERROR = -2
|
||||
DEFAULT = 1u << 16u
|
||||
};
|
||||
struct KEY {
|
||||
static char32_t const BASE = 0x0010ffff + 1;
|
||||
|
@ -145,17 +149,21 @@ public:
|
|||
static char32_t const BACKSPACE = 'H' | BASE_CONTROL;
|
||||
static char32_t const TAB = 'I' | BASE_CONTROL;
|
||||
static char32_t const ENTER = 'M' | BASE_CONTROL;
|
||||
static char32_t const ABORT = 'C' | BASE_CONTROL | BASE_META;
|
||||
};
|
||||
/*! \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,
|
||||
|
@ -164,19 +172,29 @@ public:
|
|||
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,
|
||||
LINE_NEXT,
|
||||
LINE_PREVIOUS,
|
||||
HISTORY_NEXT,
|
||||
HISTORY_PREVIOUS,
|
||||
HISTORY_FIRST,
|
||||
HISTORY_LAST,
|
||||
HISTORY_RESTORE,
|
||||
HISTORY_RESTORE_CURRENT,
|
||||
HISTORY_INCREMENTAL_SEARCH,
|
||||
HISTORY_SEEDED_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
|
||||
|
@ -308,7 +326,7 @@ public:
|
|||
* 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.lenght()`!
|
||||
* 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.
|
||||
|
@ -426,6 +444,12 @@ public:
|
|||
*/
|
||||
void set_state( State const& state );
|
||||
|
||||
/*! \brief Enable/disable case insensitive history search and completion.
|
||||
*
|
||||
* \param val - if set to non-zero then history search and completion will be case insensitive.
|
||||
*/
|
||||
void set_ignore_case( bool val );
|
||||
|
||||
/*! \brief Print formatted string to standard output.
|
||||
*
|
||||
* This function ensures proper handling of ANSI escape sequences
|
||||
|
@ -445,6 +469,14 @@ public:
|
|||
*/
|
||||
void write( char const* str, int length );
|
||||
|
||||
/*! \brief Asynchronously change the prompt while replxx_input() call is in efect.
|
||||
*
|
||||
* Can be used to change the prompt from callbacks or other threads.
|
||||
*
|
||||
* \param prompt - The prompt string to change to.
|
||||
*/
|
||||
void set_prompt( std::string prompt );
|
||||
|
||||
/*! \brief Schedule an emulated key press event.
|
||||
*
|
||||
* \param code - key press code to be emulated.
|
||||
|
@ -472,8 +504,8 @@ public:
|
|||
*
|
||||
* 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".
|
||||
* is \e Replxx::ACTION::LINE_PREVIOUS so action name to be used in this
|
||||
* interface for the same effect is "line_previous".
|
||||
*
|
||||
* \param code - handle this key-press event with following handler.
|
||||
* \param actionName - name of internal action to be invoked on key press.
|
||||
|
@ -510,6 +542,11 @@ public:
|
|||
*/
|
||||
bool history_save( std::string const& filename );
|
||||
|
||||
/*!
|
||||
* \copydoc history_save
|
||||
*/
|
||||
void history_save( std::ostream& out );
|
||||
|
||||
/*! \brief Load REPL's history from given file.
|
||||
*
|
||||
* \param filename - a path to the file which contains REPL's history that should be loaded.
|
||||
|
@ -517,6 +554,11 @@ public:
|
|||
*/
|
||||
bool history_load( std::string const& filename );
|
||||
|
||||
/*!
|
||||
* \copydoc history_load
|
||||
*/
|
||||
void history_load( std::istream& in );
|
||||
|
||||
/*! \brief Clear REPL's in-memory history.
|
||||
*/
|
||||
void history_clear( void );
|
||||
|
@ -588,6 +630,12 @@ public:
|
|||
*/
|
||||
void set_no_color( bool val );
|
||||
|
||||
/*! \brief Enable/disable (prompt width) indent for multiline entry.
|
||||
*
|
||||
* \param val - if set to true then multiline indent will be enabled.
|
||||
*/
|
||||
void set_indent_multiline( bool val );
|
||||
|
||||
/*! \brief Set maximum number of entries in history list.
|
||||
*/
|
||||
void set_max_history_size( int len );
|
||||
|
@ -601,6 +649,61 @@ private:
|
|||
Replxx& operator = ( Replxx const& ) = delete;
|
||||
};
|
||||
|
||||
/*! \brief Color definition related helper function.
|
||||
*
|
||||
* To be used to leverage 256 color terminal capabilities.
|
||||
*/
|
||||
namespace color {
|
||||
|
||||
/*! \brief Combine two color definitions to get encompassing color definition.
|
||||
*
|
||||
* To be used only for combining foreground and background colors.
|
||||
*
|
||||
* \param color1 - first input color.
|
||||
* \param color2 - second input color.
|
||||
* \return A new color definition that represent combined input colors.
|
||||
*/
|
||||
Replxx::Color operator | ( Replxx::Color color1, Replxx::Color color2 );
|
||||
|
||||
/*! \brief Transform foreground color definition into a background color definition.
|
||||
*
|
||||
* \param color - an input foreground color definition.
|
||||
* \return A background color definition that is a transformed input \e color.
|
||||
*/
|
||||
Replxx::Color bg( Replxx::Color color );
|
||||
|
||||
/*! \brief Add `bold` attribute to color definition.
|
||||
*
|
||||
* \param color - an input color definition.
|
||||
* \return A new color definition with bold attribute set.
|
||||
*/
|
||||
Replxx::Color bold( Replxx::Color color );
|
||||
|
||||
/*! \brief Add `underline` attribute to color definition.
|
||||
*
|
||||
* \param color - an input color definition.
|
||||
* \return A new color definition with underline attribute set.
|
||||
*/
|
||||
Replxx::Color underline( Replxx::Color color );
|
||||
|
||||
/*! \brief Create a new grayscale color of given brightness level.
|
||||
*
|
||||
* \param level - a brightness level for new color, must be between 0 (darkest) and 23 (brightest).
|
||||
* \return A new grayscale color of a given brightest \e level.
|
||||
*/
|
||||
Replxx::Color grayscale( int level );
|
||||
|
||||
/*! \brief Create a new color in 6×6×6 RGB color space from base component levels.
|
||||
*
|
||||
* \param red - a red (of RGB) component level, must be 0 and 5.
|
||||
* \param green - a green (of RGB) component level, must be 0 and 5.
|
||||
* \param blue - a blue (of RGB) component level, must be 0 and 5.
|
||||
* \return A new color in 6×6×6 RGB color space.
|
||||
*/
|
||||
Replxx::Color rgb666( int red, int green, int blue );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* HAVE_REPLXX_HXX_INCLUDED */
|
||||
|
|
9
third-party/replxx/src/conversion.cxx
generated
vendored
9
third-party/replxx/src/conversion.cxx
generated
vendored
|
@ -20,11 +20,6 @@ void to_lower( std::string& s_ ) {
|
|||
transform( s_.begin(), s_.end(), s_.begin(), static_cast<int(*)(int)>( &tolower ) );
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
bool is_8bit_encoding( void ) {
|
||||
bool is8BitEncoding( false );
|
||||
string origLC( setlocale( LC_CTYPE, nullptr ) );
|
||||
|
@ -42,10 +37,6 @@ bool is_8bit_encoding( void ) {
|
|||
return ( is8BitEncoding );
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
bool is8BitEncoding( is_8bit_encoding() );
|
||||
|
||||
}
|
||||
|
|
76
third-party/replxx/src/history.cxx
generated
vendored
76
third-party/replxx/src/history.cxx
generated
vendored
|
@ -1,6 +1,8 @@
|
|||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -22,6 +24,7 @@ namespace {
|
|||
void delete_ReplxxHistoryScanImpl( Replxx::HistoryScanImpl* impl_ ) {
|
||||
delete impl_;
|
||||
}
|
||||
static int const ETB = 0x17;
|
||||
}
|
||||
|
||||
static int const REPLXX_DEFAULT_HISTORY_MAX_LEN( 1000 );
|
||||
|
@ -130,7 +133,12 @@ bool History::save( std::string const& filename, bool sync_ ) {
|
|||
_entries = entries;
|
||||
reset_iters();
|
||||
}
|
||||
do_load( filename );
|
||||
/* scope for ifstream object auto-close */ {
|
||||
ifstream histFile( filename );
|
||||
if ( histFile ) {
|
||||
do_load( histFile );
|
||||
}
|
||||
}
|
||||
sort();
|
||||
remove_duplicates();
|
||||
trim_to_max_size();
|
||||
|
@ -142,13 +150,7 @@ bool History::save( std::string const& filename, bool sync_ ) {
|
|||
umask( old_umask );
|
||||
chmod( filename.c_str(), S_IRUSR | S_IWUSR );
|
||||
#endif
|
||||
Utf8String utf8;
|
||||
for ( Entry const& h : _entries ) {
|
||||
if ( ! h.text().is_empty() ) {
|
||||
utf8.assign( h.text() );
|
||||
histFile << "### " << h.timestamp() << "\n" << utf8.get() << endl;
|
||||
}
|
||||
}
|
||||
save( histFile );
|
||||
if ( ! sync_ ) {
|
||||
_entries = std::move( entries );
|
||||
_locations = std::move( locations );
|
||||
|
@ -157,6 +159,20 @@ bool History::save( std::string const& filename, bool sync_ ) {
|
|||
return ( true );
|
||||
}
|
||||
|
||||
void History::save( std::ostream& histFile ) {
|
||||
Utf8String utf8;
|
||||
UnicodeString us;
|
||||
for ( Entry& h : _entries ) {
|
||||
h.reset_scratch();
|
||||
if ( ! h.text().is_empty() ) {
|
||||
us.assign( h.text() );
|
||||
std::replace( us.begin(), us.end(), char32_t( '\n' ), char32_t( ETB ) );
|
||||
utf8.assign( us );
|
||||
histFile << "### " << h.timestamp() << "\n" << utf8.get() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool is_timestamp( std::string const& s ) {
|
||||
|
@ -179,13 +195,10 @@ bool is_timestamp( std::string const& s ) {
|
|||
|
||||
}
|
||||
|
||||
bool History::do_load( std::string const& filename ) {
|
||||
ifstream histFile( filename );
|
||||
if ( ! histFile ) {
|
||||
return ( false );
|
||||
}
|
||||
void History::do_load( std::istream& histFile ) {
|
||||
string line;
|
||||
string when( "0000-00-00 00:00:00.000" );
|
||||
UnicodeString us;
|
||||
while ( getline( histFile, line ).good() ) {
|
||||
string::size_type eol( line.find_first_of( "\r\n" ) );
|
||||
if ( eol != string::npos ) {
|
||||
|
@ -196,21 +209,31 @@ bool History::do_load( std::string const& filename ) {
|
|||
continue;
|
||||
}
|
||||
if ( ! line.empty() ) {
|
||||
_entries.emplace_back( when, UnicodeString( line ) );
|
||||
us.assign( line );
|
||||
std::replace( us.begin(), us.end(), char32_t( ETB ), char32_t( '\n' ) );
|
||||
_entries.emplace_back( when, us );
|
||||
}
|
||||
}
|
||||
return ( true );
|
||||
}
|
||||
|
||||
bool History::load( std::string const& filename ) {
|
||||
ifstream histFile( filename );
|
||||
if ( ! histFile ) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
load(histFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void History::load( std::istream& histFile ) {
|
||||
clear();
|
||||
bool success( do_load( filename ) );
|
||||
do_load( histFile );
|
||||
sort();
|
||||
remove_duplicates();
|
||||
trim_to_max_size();
|
||||
_previous = _current = last();
|
||||
_yankPos = _entries.end();
|
||||
return ( success );
|
||||
}
|
||||
|
||||
void History::sort( void ) {
|
||||
|
@ -281,11 +304,12 @@ void History::restore_pos( void ) {
|
|||
_current = _previous;
|
||||
}
|
||||
|
||||
bool History::common_prefix_search( UnicodeString const& prefix_, int prefixSize_, bool back_ ) {
|
||||
bool History::common_prefix_search( UnicodeString const& prefix_, int prefixSize_, bool back_, bool ignoreCase ) {
|
||||
int step( back_ ? -1 : 1 );
|
||||
entries_t::const_iterator it( moved( _current, step, true ) );
|
||||
entries_t::iterator it( moved( _current, step, true ) );
|
||||
bool lowerCaseContext( std::none_of( prefix_.begin(), prefix_.end(), []( char32_t x ) { return iswupper( static_cast<wint_t>( x ) ); } ) );
|
||||
while ( it != _current ) {
|
||||
if ( it->text().starts_with( prefix_.begin(), prefix_.begin() + prefixSize_ ) ) {
|
||||
if ( it->text().starts_with( prefix_.begin(), prefix_.begin() + prefixSize_, ignoreCase && lowerCaseContext ? case_insensitive_equal : case_sensitive_equal ) ) {
|
||||
_current = it;
|
||||
commit_index();
|
||||
return ( true );
|
||||
|
@ -295,7 +319,7 @@ bool History::common_prefix_search( UnicodeString const& prefix_, int prefixSize
|
|||
return ( false );
|
||||
}
|
||||
|
||||
bool History::move( entries_t::const_iterator& it_, int by_, bool wrapped_ ) const {
|
||||
bool History::move( entries_t::iterator& it_, int by_, bool wrapped_ ) {
|
||||
if ( by_ > 0 ) {
|
||||
for ( int i( 0 ); i < by_; ++ i ) {
|
||||
++ it_;
|
||||
|
@ -321,12 +345,12 @@ bool History::move( entries_t::const_iterator& it_, int by_, bool wrapped_ ) con
|
|||
return ( true );
|
||||
}
|
||||
|
||||
History::entries_t::const_iterator History::moved( entries_t::const_iterator it_, int by_, bool wrapped_ ) const {
|
||||
History::entries_t::iterator History::moved( entries_t::iterator it_, int by_, bool wrapped_ ) {
|
||||
move( it_, by_, wrapped_ );
|
||||
return ( it_ );
|
||||
}
|
||||
|
||||
void History::erase( entries_t::const_iterator it_ ) {
|
||||
void History::erase( entries_t::iterator it_ ) {
|
||||
bool invalidated( it_ == _current );
|
||||
_locations.erase( it_->text() );
|
||||
it_ = _entries.erase( it_ );
|
||||
|
@ -364,6 +388,7 @@ void History::remove_duplicates( void ) {
|
|||
_locations.clear();
|
||||
typedef std::pair<locations_t::iterator, bool> locations_insertion_result_t;
|
||||
for ( entries_t::iterator it( _entries.begin() ), end( _entries.end() ); it != end; ++ it ) {
|
||||
it->reset_scratch();
|
||||
locations_insertion_result_t locationsInsertionResult( _locations.insert( make_pair( it->text(), it ) ) );
|
||||
if ( ! locationsInsertionResult.second ) {
|
||||
_entries.erase( locationsInsertionResult.first->second );
|
||||
|
@ -382,14 +407,15 @@ void History::update_last( UnicodeString const& line_ ) {
|
|||
}
|
||||
|
||||
void History::drop_last( void ) {
|
||||
reset_current_scratch();
|
||||
erase( last() );
|
||||
}
|
||||
|
||||
bool History::is_last( void ) const {
|
||||
bool History::is_last( void ) {
|
||||
return ( _current == last() );
|
||||
}
|
||||
|
||||
History::entries_t::const_iterator History::last( void ) const {
|
||||
History::entries_t::iterator History::last( void ) {
|
||||
return ( moved( _entries.end(), -1 ) );
|
||||
}
|
||||
|
||||
|
|
45
third-party/replxx/src/history.hxx
generated
vendored
45
third-party/replxx/src/history.hxx
generated
vendored
|
@ -33,28 +33,36 @@ public:
|
|||
class Entry {
|
||||
std::string _timestamp;
|
||||
UnicodeString _text;
|
||||
UnicodeString _scratch;
|
||||
public:
|
||||
Entry( std::string const& timestamp_, UnicodeString const& text_ )
|
||||
: _timestamp( timestamp_ )
|
||||
, _text( text_ ) {
|
||||
, _text( text_ )
|
||||
, _scratch( text_ ) {
|
||||
}
|
||||
std::string const& timestamp( void ) const {
|
||||
return ( _timestamp );
|
||||
}
|
||||
UnicodeString const& text( void ) const {
|
||||
return ( _text );
|
||||
return ( _scratch );
|
||||
}
|
||||
void set_scratch( UnicodeString const& s ) {
|
||||
_scratch = s;
|
||||
}
|
||||
void reset_scratch( void ) {
|
||||
_scratch = _text;
|
||||
}
|
||||
bool operator < ( Entry const& other_ ) const {
|
||||
return ( _timestamp < other_._timestamp );
|
||||
}
|
||||
};
|
||||
typedef std::list<Entry> entries_t;
|
||||
typedef std::unordered_map<UnicodeString, entries_t::const_iterator> locations_t;
|
||||
typedef std::unordered_map<UnicodeString, entries_t::iterator> locations_t;
|
||||
private:
|
||||
entries_t _entries;
|
||||
locations_t _locations;
|
||||
int _maxSize;
|
||||
entries_t::const_iterator _current;
|
||||
entries_t::iterator _current;
|
||||
entries_t::const_iterator _yankPos;
|
||||
/*
|
||||
* _previous and _recallMostRecent are used to allow
|
||||
|
@ -64,14 +72,16 @@ private:
|
|||
* Special meaning is: a down arrow shall jump to the line one
|
||||
* after previously accepted from history.
|
||||
*/
|
||||
entries_t::const_iterator _previous;
|
||||
entries_t::iterator _previous;
|
||||
bool _recallMostRecent;
|
||||
bool _unique;
|
||||
public:
|
||||
History( void );
|
||||
void add( UnicodeString const& line, std::string const& when = now_ms_str() );
|
||||
bool save( std::string const& filename, bool );
|
||||
void save( std::ostream& histFile );
|
||||
bool load( std::string const& filename );
|
||||
void load( std::istream& histFile );
|
||||
void clear( void );
|
||||
void set_max_size( int len );
|
||||
void set_unique( bool unique_ ) {
|
||||
|
@ -92,8 +102,19 @@ public:
|
|||
}
|
||||
void update_last( UnicodeString const& );
|
||||
void drop_last( void );
|
||||
bool is_last( void ) const;
|
||||
bool is_last( void );
|
||||
bool move( bool );
|
||||
void set_current_scratch( UnicodeString const& s ) {
|
||||
_current->set_scratch( s );
|
||||
}
|
||||
void reset_scratches( void ) {
|
||||
for ( Entry& entry : _entries ) {
|
||||
entry.reset_scratch();
|
||||
}
|
||||
}
|
||||
void reset_current_scratch( void ) {
|
||||
_current->reset_scratch();
|
||||
}
|
||||
UnicodeString const& current( void ) const {
|
||||
return ( _current->text() );
|
||||
}
|
||||
|
@ -101,7 +122,7 @@ public:
|
|||
return ( _yankPos->text() );
|
||||
}
|
||||
void jump( bool, bool = true );
|
||||
bool common_prefix_search( UnicodeString const&, int, bool );
|
||||
bool common_prefix_search( UnicodeString const&, int, bool, bool );
|
||||
int size( void ) const {
|
||||
return ( static_cast<int>( _entries.size() ) );
|
||||
}
|
||||
|
@ -111,14 +132,14 @@ public:
|
|||
private:
|
||||
History( History const& ) = delete;
|
||||
History& operator = ( History const& ) = delete;
|
||||
bool move( entries_t::const_iterator&, int, bool = false ) const;
|
||||
entries_t::const_iterator moved( entries_t::const_iterator, int, bool = false ) const;
|
||||
void erase( entries_t::const_iterator );
|
||||
bool move( entries_t::iterator&, int, bool = false );
|
||||
entries_t::iterator moved( entries_t::iterator, int, bool = false );
|
||||
void erase( entries_t::iterator );
|
||||
void trim_to_max_size( void );
|
||||
void remove_duplicate( UnicodeString const& );
|
||||
void remove_duplicates( void );
|
||||
bool do_load( std::string const& );
|
||||
entries_t::const_iterator last( void ) const;
|
||||
void do_load( std::istream& );
|
||||
entries_t::iterator last( void );
|
||||
void sort( void );
|
||||
void reset_iters( void );
|
||||
};
|
||||
|
|
104
third-party/replxx/src/prompt.cxx
generated
vendored
104
third-party/replxx/src/prompt.cxx
generated
vendored
|
@ -25,14 +25,13 @@ namespace replxx {
|
|||
Prompt::Prompt( Terminal& terminal_ )
|
||||
: _extraLines( 0 )
|
||||
, _lastLinePosition( 0 )
|
||||
, _previousInputLen( 0 )
|
||||
, _previousLen( 0 )
|
||||
, _cursorRowOffset( 0 )
|
||||
, _screenColumns( 0 )
|
||||
, _terminal( terminal_ ) {
|
||||
}
|
||||
|
||||
void Prompt::write() {
|
||||
_terminal.write32( _text.get(), _byteCount );
|
||||
_terminal.write32( _text.get(), _text.length() );
|
||||
}
|
||||
|
||||
void Prompt::update_screen_columns( void ) {
|
||||
|
@ -40,77 +39,30 @@ void Prompt::update_screen_columns( void ) {
|
|||
}
|
||||
|
||||
void Prompt::set_text( UnicodeString const& text_ ) {
|
||||
_text = text_;
|
||||
update_state();
|
||||
}
|
||||
|
||||
void Prompt::update_state() {
|
||||
_cursorRowOffset -= _extraLines;
|
||||
_extraLines = 0;
|
||||
_lastLinePosition = 0;
|
||||
_previousInputLen = 0;
|
||||
_previousLen = 0;
|
||||
_screenColumns = 0;
|
||||
update_screen_columns();
|
||||
// strip control characters from the prompt -- we do allow newline
|
||||
_text = text_;
|
||||
UnicodeString::const_iterator in( text_.begin() );
|
||||
UnicodeString::iterator out( _text.begin() );
|
||||
UnicodeString::const_iterator in( _text.begin() );
|
||||
|
||||
int len = 0;
|
||||
int x = 0;
|
||||
int renderedSize( 0 );
|
||||
_characterCount = virtual_render( _text.get(), _text.length(), x, _extraLines, _screenColumns, 0, _text.get(), &renderedSize );
|
||||
_lastLinePosition = _characterCount - x;
|
||||
_text.erase( renderedSize, _text.length() - renderedSize );
|
||||
|
||||
bool const strip = !tty::out;
|
||||
_cursorRowOffset += _extraLines;
|
||||
}
|
||||
|
||||
while (in != text_.end()) {
|
||||
char32_t c = *in;
|
||||
if ('\n' == c || !is_control_code(c)) {
|
||||
*out = c;
|
||||
++out;
|
||||
++in;
|
||||
++len;
|
||||
if ('\n' == c || ++x >= _screenColumns) {
|
||||
x = 0;
|
||||
++_extraLines;
|
||||
_lastLinePosition = len;
|
||||
}
|
||||
} else if (c == '\x1b') {
|
||||
if ( strip ) {
|
||||
// jump over control chars
|
||||
++in;
|
||||
if (*in == '[') {
|
||||
++in;
|
||||
while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) {
|
||||
++in;
|
||||
}
|
||||
if (*in == 'm') {
|
||||
++in;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy control chars
|
||||
*out = *in;
|
||||
++out;
|
||||
++in;
|
||||
if (*in == '[') {
|
||||
*out = *in;
|
||||
++out;
|
||||
++in;
|
||||
while ( ( in != text_.end() ) && ( ( *in == ';' ) || ( ( ( *in >= '0' ) && ( *in <= '9' ) ) ) ) ) {
|
||||
*out = *in;
|
||||
++out;
|
||||
++in;
|
||||
}
|
||||
if (*in == 'm') {
|
||||
*out = *in;
|
||||
++out;
|
||||
++in;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
++in;
|
||||
}
|
||||
}
|
||||
_characterCount = len;
|
||||
_byteCount = static_cast<int>(out - _text.begin());
|
||||
|
||||
_indentation = len - _lastLinePosition;
|
||||
_cursorRowOffset = _extraLines;
|
||||
int Prompt::indentation() const {
|
||||
return _characterCount - _lastLinePosition;
|
||||
}
|
||||
|
||||
// Used with DynamicPrompt (history search)
|
||||
|
@ -123,31 +75,15 @@ DynamicPrompt::DynamicPrompt( Terminal& terminal_, int initialDirection )
|
|||
: Prompt( terminal_ )
|
||||
, _searchText()
|
||||
, _direction( initialDirection ) {
|
||||
update_screen_columns();
|
||||
_cursorRowOffset = 0;
|
||||
const UnicodeString* basePrompt =
|
||||
(_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
|
||||
size_t promptStartLength = basePrompt->length();
|
||||
_characterCount = static_cast<int>(promptStartLength + endSearchBasePrompt.length());
|
||||
_byteCount = _characterCount;
|
||||
_lastLinePosition = _characterCount; // TODO fix this, we are asssuming
|
||||
// that the history prompt won't wrap (!)
|
||||
_previousLen = _characterCount;
|
||||
_text.assign( *basePrompt ).append( endSearchBasePrompt );
|
||||
calculate_screen_position(
|
||||
0, 0, screen_columns(), _characterCount,
|
||||
_indentation, _extraLines
|
||||
);
|
||||
updateSearchPrompt();
|
||||
}
|
||||
|
||||
void DynamicPrompt::updateSearchPrompt(void) {
|
||||
update_screen_columns();
|
||||
const UnicodeString* basePrompt =
|
||||
(_direction > 0) ? &forwardSearchBasePrompt : &reverseSearchBasePrompt;
|
||||
size_t promptStartLength = basePrompt->length();
|
||||
_characterCount = static_cast<int>(promptStartLength + _searchText.length() +
|
||||
endSearchBasePrompt.length());
|
||||
_byteCount = _characterCount;
|
||||
_text.assign( *basePrompt ).append( _searchText ).append( endSearchBasePrompt );
|
||||
update_state();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
21
third-party/replxx/src/prompt.hxx
generated
vendored
21
third-party/replxx/src/prompt.hxx
generated
vendored
|
@ -8,28 +8,27 @@
|
|||
|
||||
namespace replxx {
|
||||
|
||||
class Prompt { // a convenience struct for grouping prompt info
|
||||
class Prompt { // a convenience struct for grouping prompt info
|
||||
public:
|
||||
UnicodeString _text; // our copy of the prompt text, edited
|
||||
int _characterCount; // chars in _text
|
||||
int _byteCount; // bytes in _text
|
||||
int _extraLines; // extra lines (beyond 1) occupied by prompt
|
||||
int _indentation; // column offset to end of prompt
|
||||
int _lastLinePosition; // index into _text where last line begins
|
||||
int _previousInputLen; // _characterCount of previous input line, for clearing
|
||||
int _cursorRowOffset; // where the cursor is relative to the start of the prompt
|
||||
int _previousLen; // help erasing
|
||||
UnicodeString _text; // our copy of the prompt text, edited
|
||||
int _characterCount{0}; // visible characters in _text
|
||||
int _extraLines{0}; // extra lines (beyond 1) occupied by prompt
|
||||
int _lastLinePosition{0}; // index into _text where last line begins
|
||||
int _cursorRowOffset{0}; // where the cursor is relative to the start of the prompt
|
||||
|
||||
private:
|
||||
int _screenColumns; // width of screen in columns [cache]
|
||||
int _screenColumns{0}; // width of screen in columns [cache]
|
||||
Terminal& _terminal;
|
||||
public:
|
||||
Prompt( Terminal& );
|
||||
void set_text( UnicodeString const& textPtr );
|
||||
void update_state();
|
||||
void update_screen_columns( void );
|
||||
int screen_columns() const {
|
||||
return ( _screenColumns );
|
||||
}
|
||||
void write();
|
||||
int indentation() const;
|
||||
};
|
||||
|
||||
// changing prompt for "(reverse-i-search)`text':" etc.
|
||||
|
|
97
third-party/replxx/src/replxx.cxx
generated
vendored
97
third-party/replxx/src/replxx.cxx
generated
vendored
|
@ -162,10 +162,18 @@ bool Replxx::history_save( std::string const& filename ) {
|
|||
return ( _impl->history_save( filename ) );
|
||||
}
|
||||
|
||||
void Replxx::history_save( std::ostream& out ) {
|
||||
_impl->history_save( out );
|
||||
}
|
||||
|
||||
bool Replxx::history_load( std::string const& filename ) {
|
||||
return ( _impl->history_load( filename ) );
|
||||
}
|
||||
|
||||
void Replxx::history_load( std::istream& in ) {
|
||||
_impl->history_load( in );
|
||||
}
|
||||
|
||||
void Replxx::history_clear( void ) {
|
||||
_impl->history_clear();
|
||||
}
|
||||
|
@ -222,6 +230,10 @@ void Replxx::set_no_color( bool val ) {
|
|||
_impl->set_no_color( val );
|
||||
}
|
||||
|
||||
void Replxx::set_indent_multiline( bool val ) {
|
||||
_impl->set_indent_multiline( val );
|
||||
}
|
||||
|
||||
void Replxx::set_max_history_size( int len ) {
|
||||
_impl->set_max_history_size( len );
|
||||
}
|
||||
|
@ -254,6 +266,10 @@ void Replxx::set_state( Replxx::State const& state_ ) {
|
|||
_impl->set_state( state_ );
|
||||
}
|
||||
|
||||
void Replxx::set_ignore_case( bool val ) {
|
||||
_impl->set_ignore_case( val );
|
||||
}
|
||||
|
||||
int Replxx::install_window_change_handler( void ) {
|
||||
return ( _impl->install_window_change_handler() );
|
||||
}
|
||||
|
@ -282,6 +298,45 @@ void Replxx::write( char const* str, int length ) {
|
|||
return ( _impl->print( str, length ) );
|
||||
}
|
||||
|
||||
void Replxx::set_prompt( std::string prompt ) {
|
||||
return ( _impl->set_prompt( std::move( prompt ) ) );
|
||||
}
|
||||
|
||||
namespace color {
|
||||
|
||||
Replxx::Color operator | ( Replxx::Color color1_, Replxx::Color color2_ ) {
|
||||
return static_cast<Replxx::Color>( static_cast<int unsigned>( color1_ ) | static_cast<int unsigned>( color2_ ) );
|
||||
}
|
||||
|
||||
Replxx::Color bg( Replxx::Color color_ ) {
|
||||
return static_cast<Replxx::Color>( ( ( static_cast<int unsigned>( color_ ) & 0xFFu ) << 8 ) | color::BACKGROUND_COLOR_SET );
|
||||
}
|
||||
|
||||
Replxx::Color bold( Replxx::Color color_ ) {
|
||||
return static_cast<Replxx::Color>( static_cast<int unsigned>( color_ ) | color::BOLD );
|
||||
}
|
||||
|
||||
Replxx::Color underline( Replxx::Color color_ ) {
|
||||
return static_cast<Replxx::Color>( static_cast<int unsigned>( color_ ) | color::UNDERLINE );
|
||||
}
|
||||
|
||||
Replxx::Color grayscale( int level_ ) {
|
||||
assert( ( level_ >= 0 ) && ( level_ < 24 ) );
|
||||
return static_cast<Replxx::Color>( abs( level_ ) % 24 + static_cast<int unsigned>( color::GRAYSCALE ) );
|
||||
}
|
||||
|
||||
Replxx::Color rgb666( int red_, int green_, int blue_ ) {
|
||||
assert( ( red_ >= 0 ) && ( red_ < 6 ) && ( green_ >= 0 ) && ( green_ < 6 ) && ( blue_ >= 0 ) && ( blue_ < 6 ) );
|
||||
return static_cast<Replxx::Color>(
|
||||
( abs( red_ ) % 6 ) * 36
|
||||
+ ( abs( green_ ) % 6 ) * 6
|
||||
+ ( abs( blue_ ) % 6 )
|
||||
+ static_cast<int unsigned>( color::RGB666 )
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
::Replxx* replxx_init() {
|
||||
|
@ -339,6 +394,11 @@ void replxx_set_state( ::Replxx* replxx_, ReplxxState* state ) {
|
|||
replxx->set_state( replxx::Replxx::State( state->text, state->cursorPosition ) );
|
||||
}
|
||||
|
||||
void replxx_set_ignore_case( ::Replxx* replxx_, int val ) {
|
||||
replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
|
||||
replxx->set_ignore_case( val );
|
||||
}
|
||||
|
||||
/**
|
||||
* replxx_set_preload_buffer provides text to be inserted into the command buffer
|
||||
*
|
||||
|
@ -395,6 +455,11 @@ int replxx_write( ::Replxx* replxx_, char const* str, int length ) {
|
|||
return static_cast<int>( length );
|
||||
}
|
||||
|
||||
void replxx_set_prompt( ::Replxx* replxx_, const char* prompt ) {
|
||||
replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
|
||||
replxx->set_prompt( prompt );
|
||||
}
|
||||
|
||||
struct replxx_completions {
|
||||
replxx::Replxx::completions_t data;
|
||||
};
|
||||
|
@ -478,7 +543,7 @@ void replxx_add_completion( replxx_completions* lc, const char* str ) {
|
|||
lc->data.emplace_back( str );
|
||||
}
|
||||
|
||||
void replxx_add_completion( replxx_completions* lc, const char* str, ReplxxColor color ) {
|
||||
void replxx_add_color_completion( replxx_completions* lc, const char* str, ReplxxColor color ) {
|
||||
lc->data.emplace_back( str, static_cast<replxx::Replxx::Color>( color ) );
|
||||
}
|
||||
|
||||
|
@ -527,6 +592,11 @@ void replxx_set_no_color( ::Replxx* replxx_, int val ) {
|
|||
replxx->set_no_color( val ? true : false );
|
||||
}
|
||||
|
||||
void replxx_set_indent_multiline( ::Replxx* replxx_, int val ) {
|
||||
replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
|
||||
replxx->set_indent_multiline( val ? true : false );
|
||||
}
|
||||
|
||||
void replxx_set_beep_on_ambiguous_completion( ::Replxx* replxx_, int val ) {
|
||||
replxx::Replxx::ReplxxImpl* replxx( reinterpret_cast<replxx::Replxx::ReplxxImpl*>( replxx_ ) );
|
||||
replxx->set_beep_on_ambiguous_completion( val ? true : false );
|
||||
|
@ -646,3 +716,28 @@ int replxx_install_window_change_handler( ::Replxx* replxx_ ) {
|
|||
return ( replxx->install_window_change_handler() );
|
||||
}
|
||||
|
||||
using namespace replxx::color;
|
||||
ReplxxColor replxx_color_combine( ReplxxColor color1_, ReplxxColor color2_ ) {
|
||||
return static_cast<ReplxxColor>( static_cast<replxx::Replxx::Color>( color1_ ) | static_cast<replxx::Replxx::Color>( color2_ ) );
|
||||
}
|
||||
|
||||
ReplxxColor replxx_color_bg( ReplxxColor color_ ) {
|
||||
return static_cast<ReplxxColor>( color::bg( static_cast<replxx::Replxx::Color>( color_ ) ) );
|
||||
}
|
||||
|
||||
ReplxxColor replxx_color_bold( ReplxxColor color_ ) {
|
||||
return static_cast<ReplxxColor>( color::bold( static_cast<replxx::Replxx::Color>( color_ ) ) );
|
||||
}
|
||||
|
||||
ReplxxColor replxx_color_underline( ReplxxColor color_ ) {
|
||||
return static_cast<ReplxxColor>( color::underline( static_cast<replxx::Replxx::Color>( color_ ) ) );
|
||||
}
|
||||
|
||||
ReplxxColor replxx_color_grayscale( int level_ ) {
|
||||
return static_cast<ReplxxColor>( color::grayscale( level_ ) );
|
||||
}
|
||||
|
||||
ReplxxColor replxx_color_rgb666( int r_, int g_, int b_ ) {
|
||||
return static_cast<ReplxxColor>( color::rgb666( r_, g_, b_ ) );
|
||||
}
|
||||
|
||||
|
|
1025
third-party/replxx/src/replxx_impl.cxx
generated
vendored
1025
third-party/replxx/src/replxx_impl.cxx
generated
vendored
File diff suppressed because it is too large
Load diff
62
third-party/replxx/src/replxx_impl.hxx
generated
vendored
62
third-party/replxx/src/replxx_impl.hxx
generated
vendored
|
@ -39,6 +39,7 @@
|
|||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "replxx.hxx"
|
||||
#include "history.hxx"
|
||||
|
@ -74,10 +75,10 @@ public:
|
|||
}
|
||||
};
|
||||
typedef std::vector<Completion> completions_t;
|
||||
typedef std::vector<UnicodeString> data_t;
|
||||
typedef std::vector<UnicodeString> hints_t;
|
||||
typedef std::unique_ptr<char[]> utf8_buffer_t;
|
||||
typedef std::unique_ptr<char32_t[]> input_buffer_t;
|
||||
typedef std::vector<char> char_widths_t;
|
||||
typedef std::vector<char32_t> display_t;
|
||||
typedef std::deque<char32_t> key_presses_t;
|
||||
typedef std::deque<std::string> messages_t;
|
||||
|
@ -92,22 +93,22 @@ public:
|
|||
typedef std::unordered_map<int, Replxx::key_press_handler_t> key_press_handlers_t;
|
||||
private:
|
||||
typedef int long long unsigned action_trait_t;
|
||||
static action_trait_t const NOOP = 0;
|
||||
static action_trait_t const WANT_REFRESH = 1;
|
||||
static action_trait_t const RESET_KILL_ACTION = 2;
|
||||
static action_trait_t const SET_KILL_ACTION = 4;
|
||||
static action_trait_t const DONT_RESET_PREFIX = 8;
|
||||
static action_trait_t const DONT_RESET_COMPLETIONS = 16;
|
||||
static action_trait_t const HISTORY_RECALL_MOST_RECENT = 32;
|
||||
static action_trait_t const DONT_RESET_HIST_YANK_INDEX = 64;
|
||||
static action_trait_t const NOOP = 0;
|
||||
static action_trait_t const WANT_REFRESH = 1;
|
||||
static action_trait_t const MOVE_CURSOR = 2;
|
||||
static action_trait_t const RESET_KILL_ACTION = 4;
|
||||
static action_trait_t const SET_KILL_ACTION = 8;
|
||||
static action_trait_t const DONT_RESET_PREFIX = 16;
|
||||
static action_trait_t const DONT_RESET_COMPLETIONS = 32;
|
||||
static action_trait_t const HISTORY_RECALL_MOST_RECENT = 64;
|
||||
static action_trait_t const DONT_RESET_HIST_YANK_INDEX = 128;
|
||||
private:
|
||||
mutable Utf8String _utf8Buffer;
|
||||
UnicodeString _data;
|
||||
char_widths_t _charWidths; // character widths from mk_wcwidth()
|
||||
int _pos; // character position in buffer ( 0 <= _pos <= _data[_line].length() )
|
||||
display_t _display;
|
||||
int _displayInputLength;
|
||||
UnicodeString _hint;
|
||||
int _pos; // character position in buffer ( 0 <= _pos <= _len )
|
||||
int _prefix; // prefix length used in common prefix search
|
||||
int _hintSelection; // Currently selected hint.
|
||||
History _history;
|
||||
|
@ -117,7 +118,8 @@ private:
|
|||
int _lastYankSize;
|
||||
int _maxHintRows;
|
||||
int _hintDelay;
|
||||
std::string _breakChars;
|
||||
std::string _wordBreakChars;
|
||||
std::string _subwordBreakChars;
|
||||
int _completionCountCutoff;
|
||||
bool _overwrite;
|
||||
bool _doubleTabCompletion;
|
||||
|
@ -126,6 +128,7 @@ private:
|
|||
bool _immediateCompletion;
|
||||
bool _bracketedPaste;
|
||||
bool _noColor;
|
||||
bool _indentMultiline;
|
||||
named_actions_t _namedActions;
|
||||
key_press_handlers_t _keyPressHandlers;
|
||||
Terminal _terminal;
|
||||
|
@ -137,6 +140,8 @@ private:
|
|||
Replxx::hint_callback_t _hintCallback;
|
||||
key_presses_t _keyPresses;
|
||||
messages_t _messages;
|
||||
std::string _asyncPrompt;
|
||||
bool _updatePrompt;
|
||||
completions_t _completions;
|
||||
int _completionContextLength;
|
||||
int _completionSelection;
|
||||
|
@ -148,6 +153,10 @@ private:
|
|||
hints_t _hintsCache;
|
||||
int _hintContextLenght;
|
||||
Utf8String _hintSeed;
|
||||
bool _hasNewlines;
|
||||
int _oldPos;
|
||||
bool _moveCursor;
|
||||
bool _ignoreCase;
|
||||
mutable std::mutex _mutex;
|
||||
public:
|
||||
ReplxxImpl( FILE*, FILE*, FILE* );
|
||||
|
@ -160,12 +169,15 @@ public:
|
|||
void history_add( std::string const& line );
|
||||
bool history_sync( std::string const& filename );
|
||||
bool history_save( std::string const& filename );
|
||||
void history_save( std::ostream& out );
|
||||
bool history_load( std::string const& filename );
|
||||
void history_load( std::istream& in );
|
||||
void history_clear( void );
|
||||
Replxx::HistoryScan::impl_t history_scan( void ) const;
|
||||
int history_size( void ) const;
|
||||
void set_preload_buffer(std::string const& preloadText);
|
||||
void set_word_break_characters( char const* wordBreakers );
|
||||
void set_subword_break_characters( char const* subwordBreakers );
|
||||
void set_max_hint_rows( int count );
|
||||
void set_hint_delay( int milliseconds );
|
||||
void set_double_tab_completion( bool val );
|
||||
|
@ -174,12 +186,14 @@ public:
|
|||
void set_immediate_completion( bool val );
|
||||
void set_unique_history( bool );
|
||||
void set_no_color( bool val );
|
||||
void set_indent_multiline( bool val );
|
||||
void set_max_history_size( int len );
|
||||
void set_completion_count_cutoff( int len );
|
||||
int install_window_change_handler( void );
|
||||
void enable_bracketed_paste( void );
|
||||
void disable_bracketed_paste( void );
|
||||
void print( char const*, int );
|
||||
void set_prompt( std::string prompt );
|
||||
Replxx::ACTION_RESULT clear_screen( char32_t );
|
||||
void emulate_key_press( char32_t );
|
||||
Replxx::ACTION_RESULT invoke( Replxx::ACTION, char32_t );
|
||||
|
@ -187,6 +201,7 @@ public:
|
|||
void bind_key_internal( char32_t, char const* );
|
||||
Replxx::State get_state( void ) const;
|
||||
void set_state( Replxx::State const& );
|
||||
void set_ignore_case( bool val );
|
||||
private:
|
||||
ReplxxImpl( ReplxxImpl const& ) = delete;
|
||||
ReplxxImpl& operator = ( ReplxxImpl const& ) = delete;
|
||||
|
@ -195,13 +210,18 @@ private:
|
|||
int get_input_line( void );
|
||||
Replxx::ACTION_RESULT action( action_trait_t, key_press_handler_raw_t const&, char32_t );
|
||||
Replxx::ACTION_RESULT insert_character( char32_t );
|
||||
Replxx::ACTION_RESULT new_line( char32_t );
|
||||
Replxx::ACTION_RESULT go_to_begining_of_line( char32_t );
|
||||
Replxx::ACTION_RESULT go_to_end_of_line( char32_t );
|
||||
Replxx::ACTION_RESULT move_one_char_left( char32_t );
|
||||
Replxx::ACTION_RESULT move_one_char_right( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT move_one_word_left( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT move_one_word_right( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT kill_word_to_left( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT kill_word_to_right( char32_t );
|
||||
Replxx::ACTION_RESULT kill_to_whitespace_to_left( char32_t );
|
||||
Replxx::ACTION_RESULT kill_to_begining_of_line( char32_t );
|
||||
|
@ -209,8 +229,11 @@ private:
|
|||
Replxx::ACTION_RESULT yank( char32_t );
|
||||
Replxx::ACTION_RESULT yank_cycle( char32_t );
|
||||
Replxx::ACTION_RESULT yank_last_arg( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT capitalize_word( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT lowercase_word( char32_t );
|
||||
template <bool subword>
|
||||
Replxx::ACTION_RESULT uppercase_word( char32_t );
|
||||
Replxx::ACTION_RESULT transpose_characters( char32_t );
|
||||
Replxx::ACTION_RESULT abort_line( char32_t );
|
||||
|
@ -218,11 +241,15 @@ private:
|
|||
Replxx::ACTION_RESULT delete_character( char32_t );
|
||||
Replxx::ACTION_RESULT backspace_character( char32_t );
|
||||
Replxx::ACTION_RESULT commit_line( char32_t );
|
||||
Replxx::ACTION_RESULT line_next( char32_t );
|
||||
Replxx::ACTION_RESULT line_previous( char32_t );
|
||||
Replxx::ACTION_RESULT history_next( char32_t );
|
||||
Replxx::ACTION_RESULT history_previous( char32_t );
|
||||
Replxx::ACTION_RESULT history_move( bool );
|
||||
Replxx::ACTION_RESULT history_first( char32_t );
|
||||
Replxx::ACTION_RESULT history_last( char32_t );
|
||||
Replxx::ACTION_RESULT history_restore( char32_t );
|
||||
Replxx::ACTION_RESULT history_restore_current( char32_t );
|
||||
Replxx::ACTION_RESULT history_jump( bool );
|
||||
Replxx::ACTION_RESULT hint_next( char32_t );
|
||||
Replxx::ACTION_RESULT hint_previous( char32_t );
|
||||
|
@ -246,15 +273,22 @@ private:
|
|||
completions_t call_completer( std::string const& input, int& ) const;
|
||||
hints_t call_hinter( std::string const& input, int&, Replxx::Color& color ) const;
|
||||
void refresh_line( HINT_ACTION = HINT_ACTION::REGENERATE );
|
||||
void move_cursor( void );
|
||||
void indent( void );
|
||||
int virtual_render( char32_t const*, int, int&, int&, Prompt const* = nullptr );
|
||||
void render( char32_t );
|
||||
void render( HINT_ACTION );
|
||||
int handle_hints( HINT_ACTION );
|
||||
void handle_hints( HINT_ACTION );
|
||||
void set_color( Replxx::Color );
|
||||
int context_length( void );
|
||||
int prev_newline_position( int ) const;
|
||||
int next_newline_position( int ) const;
|
||||
int pos_in_line( void ) const;
|
||||
void clear( void );
|
||||
void repaint( void );
|
||||
template <bool subword>
|
||||
bool is_word_break_character( char32_t ) const;
|
||||
void dynamicRefresh(Prompt& pi, char32_t* buf32, int len, int pos);
|
||||
void dynamic_refresh(Prompt& oldPrompt, Prompt& newPrompt, char32_t* buf32, int len, int pos);
|
||||
char const* finalize_input( char const* );
|
||||
void clear_self_to_end_of_screen( Prompt const* = nullptr );
|
||||
typedef struct {
|
||||
|
|
199
third-party/replxx/src/terminal.cxx
generated
vendored
199
third-party/replxx/src/terminal.cxx
generated
vendored
|
@ -95,6 +95,7 @@ Terminal::Terminal( void )
|
|||
, _empty()
|
||||
#else
|
||||
: _origTermios()
|
||||
, _rawModeTermios()
|
||||
, _interrupt()
|
||||
#endif
|
||||
, _rawMode( false )
|
||||
|
@ -126,11 +127,13 @@ void Terminal::write32( char32_t const* text32, int len32 ) {
|
|||
|
||||
void Terminal::write8( char const* data_, int size_ ) {
|
||||
#ifdef _WIN32
|
||||
if ( ! _rawMode ) {
|
||||
bool temporarilyEnabled( false );
|
||||
if ( _consoleOut == INVALID_HANDLE_VALUE ) {
|
||||
enable_out();
|
||||
temporarilyEnabled = true;
|
||||
}
|
||||
int nWritten( win_write( _consoleOut, _autoEscape, data_, size_ ) );
|
||||
if ( ! _rawMode ) {
|
||||
if ( temporarilyEnabled ) {
|
||||
disable_out();
|
||||
}
|
||||
#else
|
||||
|
@ -179,8 +182,8 @@ inline int notty( void ) {
|
|||
|
||||
void Terminal::enable_out( void ) {
|
||||
#ifdef _WIN32
|
||||
_consoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
SetConsoleOutputCP( 65001 );
|
||||
_consoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
GetConsoleMode( _consoleOut, &_origOutMode );
|
||||
_autoEscape = SetConsoleMode( _consoleOut, _origOutMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING ) != 0;
|
||||
#endif
|
||||
|
@ -206,70 +209,88 @@ void Terminal::disable_bracketed_paste( void ) {
|
|||
}
|
||||
|
||||
int Terminal::enable_raw_mode( void ) {
|
||||
if ( ! _rawMode ) {
|
||||
#ifdef _WIN32
|
||||
_consoleIn = GetStdHandle( STD_INPUT_HANDLE );
|
||||
SetConsoleCP( 65001 );
|
||||
GetConsoleMode( _consoleIn, &_origInMode );
|
||||
SetConsoleMode(
|
||||
_consoleIn,
|
||||
_origInMode & ~( ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT )
|
||||
);
|
||||
enable_out();
|
||||
#else
|
||||
struct termios raw;
|
||||
|
||||
if ( ! tty::in ) {
|
||||
return ( notty() );
|
||||
}
|
||||
if ( tcgetattr( 0, &_origTermios ) == -1 ) {
|
||||
return ( notty() );
|
||||
}
|
||||
|
||||
raw = _origTermios; /* modify the original mode */
|
||||
/* input modes: no break, no CR to NL, no parity check, no strip char,
|
||||
* no start/stop output control. */
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
/* output modes - disable post processing */
|
||||
// this is wrong, we don't want raw output, it turns newlines into straight
|
||||
// linefeeds
|
||||
// raw.c_oflag &= ~(OPOST);
|
||||
/* control modes - set 8 bit chars */
|
||||
raw.c_cflag |= (CS8);
|
||||
/* local modes - echoing off, canonical off, no extended functions,
|
||||
* no signal chars (^Z,^C) */
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
/* control chars - set return condition: min number of bytes and timer.
|
||||
* We want read to return every single byte, without timeout. */
|
||||
raw.c_cc[VMIN] = 1;
|
||||
raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
|
||||
|
||||
/* put terminal in raw mode after flushing */
|
||||
if ( tcsetattr(0, TCSADRAIN, &raw) < 0 ) {
|
||||
return ( notty() );
|
||||
}
|
||||
_terminal_ = this;
|
||||
#endif
|
||||
_rawMode = true;
|
||||
if ( _rawMode ) {
|
||||
return ( 0 );
|
||||
}
|
||||
#ifdef _WIN32
|
||||
_consoleIn = GetStdHandle( STD_INPUT_HANDLE );
|
||||
GetConsoleMode( _consoleIn, &_origInMode );
|
||||
#else
|
||||
|
||||
if ( ! tty::in ) {
|
||||
return ( notty() );
|
||||
}
|
||||
if ( tcgetattr( 0, &_origTermios ) == -1 ) {
|
||||
return ( notty() );
|
||||
}
|
||||
|
||||
_rawModeTermios = _origTermios; /* modify the original mode */
|
||||
/* input modes: no break, no CR to NL, no parity check, no strip char,
|
||||
* no start/stop output control. */
|
||||
_rawModeTermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
/* output modes - disable post processing */
|
||||
// this is wrong, we don't want _rawModeTermios output, it turns newlines into straight
|
||||
// linefeeds
|
||||
// _rawModeTermios.c_oflag &= ~(OPOST);
|
||||
/* control modes - set 8 bit chars */
|
||||
_rawModeTermios.c_cflag |= (CS8);
|
||||
/* local modes - echoing off, canonical off, no extended functions,
|
||||
* no signal chars (^Z,^C) */
|
||||
_rawModeTermios.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
/* control chars - set return condition: min number of bytes and timer.
|
||||
* We want read to return every single byte, without timeout. */
|
||||
_rawModeTermios.c_cc[VMIN] = 1;
|
||||
_rawModeTermios.c_cc[VTIME] = 0; /* 1 byte, no timer */
|
||||
|
||||
#endif
|
||||
|
||||
_rawMode = true;
|
||||
if ( reset_raw_mode() < 0 ) {
|
||||
_rawMode = false;
|
||||
return ( notty() );
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
_terminal_ = this;
|
||||
#endif
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
void Terminal::disable_raw_mode(void) {
|
||||
if ( _rawMode ) {
|
||||
#ifdef _WIN32
|
||||
disable_out();
|
||||
SetConsoleMode( _consoleIn, _origInMode );
|
||||
SetConsoleCP( _inputCodePage );
|
||||
_consoleIn = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
_terminal_ = nullptr;
|
||||
if ( tcsetattr( 0, TCSADRAIN, &_origTermios ) == -1 ) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_rawMode = false;
|
||||
int Terminal::reset_raw_mode( void ) {
|
||||
if ( ! _rawMode ) {
|
||||
return ( -1 );
|
||||
}
|
||||
#ifdef _WIN32
|
||||
SetConsoleMode(
|
||||
_consoleIn,
|
||||
( _origInMode & ~( ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT ) ) | ENABLE_QUICK_EDIT_MODE
|
||||
);
|
||||
SetConsoleCP( 65001 );
|
||||
enable_out();
|
||||
return ( 0 );
|
||||
#else
|
||||
/* put terminal in raw mode after flushing */
|
||||
return ( tcsetattr( 0, TCSADRAIN, &_rawModeTermios ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Terminal::disable_raw_mode(void) {
|
||||
if ( ! _rawMode ) {
|
||||
return;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
disable_out();
|
||||
SetConsoleMode( _consoleIn, _origInMode );
|
||||
SetConsoleCP( _inputCodePage );
|
||||
_consoleIn = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
_terminal_ = nullptr;
|
||||
if ( tcsetattr( 0, TCSADRAIN, &_origTermios ) == -1 ) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_rawMode = false;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -390,7 +411,10 @@ char32_t Terminal::read_char( void ) {
|
|||
}
|
||||
int key( rec.Event.KeyEvent.uChar.UnicodeChar );
|
||||
if ( key == 0 ) {
|
||||
switch (rec.Event.KeyEvent.wVirtualKeyCode) {
|
||||
if ( rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ) {
|
||||
modifierKeys |= Replxx::KEY::BASE_SHIFT;
|
||||
}
|
||||
switch ( rec.Event.KeyEvent.wVirtualKeyCode ) {
|
||||
case VK_LEFT:
|
||||
return modifierKeys | Replxx::KEY::LEFT;
|
||||
case VK_RIGHT:
|
||||
|
@ -443,6 +467,9 @@ char32_t Terminal::read_char( void ) {
|
|||
highSurrogate = key - 0xD800;
|
||||
continue;
|
||||
} else {
|
||||
if ( ( key == 13 ) && ( rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ) ) {
|
||||
key = 10;
|
||||
}
|
||||
// we got a real character, return it
|
||||
if ( ( key >= 0xDC00 ) && ( key <= 0xDFFF ) ) {
|
||||
key -= 0xDC00;
|
||||
|
@ -535,7 +562,7 @@ char32_t Terminal::read_char( void ) {
|
|||
|
||||
Terminal::EVENT_TYPE Terminal::wait_for_input( int long timeout_ ) {
|
||||
#ifdef _WIN32
|
||||
std::array<HANDLE,2> handles = { _consoleIn, _interrupt };
|
||||
std::array<HANDLE, 2> handles = { _consoleIn, _interrupt };
|
||||
while ( true ) {
|
||||
DWORD event( WaitForMultipleObjects( static_cast<DWORD>( handles.size() ), handles.data(), false, timeout_ > 0 ? timeout_ : INFINITE ) );
|
||||
switch ( event ) {
|
||||
|
@ -552,22 +579,34 @@ Terminal::EVENT_TYPE Terminal::wait_for_input( int long timeout_ ) {
|
|||
// read the event to unsignal the handle
|
||||
ReadConsoleInputW( _consoleIn, &rec, 1, &count );
|
||||
continue;
|
||||
} else if (rec.EventType == KEY_EVENT) {
|
||||
int key(rec.Event.KeyEvent.uChar.UnicodeChar);
|
||||
if (key == 0) {
|
||||
switch (rec.Event.KeyEvent.wVirtualKeyCode) {
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
case VK_UP:
|
||||
case VK_DOWN:
|
||||
case VK_DELETE:
|
||||
case VK_HOME:
|
||||
case VK_END:
|
||||
case VK_PRIOR:
|
||||
case VK_NEXT:
|
||||
} else if ( rec.EventType == KEY_EVENT ) {
|
||||
int key( rec.Event.KeyEvent.uChar.UnicodeChar );
|
||||
if ( key == 0 ) {
|
||||
switch ( rec.Event.KeyEvent.wVirtualKeyCode ) {
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
case VK_UP:
|
||||
case VK_DOWN:
|
||||
case VK_DELETE:
|
||||
case VK_HOME:
|
||||
case VK_END:
|
||||
case VK_PRIOR:
|
||||
case VK_NEXT:
|
||||
case VK_F1:
|
||||
case VK_F2:
|
||||
case VK_F3:
|
||||
case VK_F4:
|
||||
case VK_F5:
|
||||
case VK_F6:
|
||||
case VK_F7:
|
||||
case VK_F8:
|
||||
case VK_F9:
|
||||
case VK_F10:
|
||||
case VK_F11:
|
||||
case VK_F12:
|
||||
break;
|
||||
default:
|
||||
ReadConsoleInputW(_consoleIn, &rec, 1, &count);
|
||||
default:
|
||||
ReadConsoleInputW( _consoleIn, &rec, 1, &count );
|
||||
continue; // in raw mode, ReadConsoleInput shows shift, ctrl - ignore them
|
||||
}
|
||||
}
|
||||
|
@ -665,7 +704,7 @@ void Terminal::clear_screen( CLEAR_SCREEN clearScreen_ ) {
|
|||
_empty.resize( toWrite - 1, ' ' );
|
||||
WriteConsoleA( consoleOut, _empty.data(), toWrite - 1, &nWritten, nullptr );
|
||||
} else {
|
||||
COORD scrollTarget = { 0, -inf.dwSize.Y };
|
||||
COORD scrollTarget = { 0, static_cast<SHORT>( -inf.dwSize.Y ) };
|
||||
CHAR_INFO fill{ TEXT( ' ' ), inf.wAttributes };
|
||||
SMALL_RECT scrollRect = { 0, 0, inf.dwSize.X, inf.dwSize.Y };
|
||||
ScrollConsoleScreenBuffer( consoleOut, &scrollRect, nullptr, scrollTarget, &fill );
|
||||
|
|
2
third-party/replxx/src/terminal.hxx
generated
vendored
2
third-party/replxx/src/terminal.hxx
generated
vendored
|
@ -38,6 +38,7 @@ private:
|
|||
std::vector<char> _empty;
|
||||
#else
|
||||
struct termios _origTermios; /* in order to restore at exit */
|
||||
struct termios _rawModeTermios; /* in order to reset raw mode after callbacks */
|
||||
int _interrupt[2];
|
||||
#endif
|
||||
bool _rawMode; /* for destructor to check if restore is needed */
|
||||
|
@ -57,6 +58,7 @@ public:
|
|||
void enable_bracketed_paste( void );
|
||||
void disable_bracketed_paste( void );
|
||||
int enable_raw_mode(void);
|
||||
int reset_raw_mode(void);
|
||||
void disable_raw_mode(void);
|
||||
char32_t read_char(void);
|
||||
void clear_screen( CLEAR_SCREEN );
|
||||
|
|
41
third-party/replxx/src/unicodestring.hxx
generated
vendored
41
third-party/replxx/src/unicodestring.hxx
generated
vendored
|
@ -3,11 +3,21 @@
|
|||
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cwctype>
|
||||
#include <cassert>
|
||||
|
||||
#include "conversion.hxx"
|
||||
|
||||
namespace replxx {
|
||||
|
||||
inline bool case_sensitive_equal( char32_t l, char32_t r ) {
|
||||
return l == r;
|
||||
}
|
||||
|
||||
inline bool case_insensitive_equal( char32_t l, char32_t r ) {
|
||||
return towlower( static_cast<wint_t>( l ) ) == towlower( static_cast<wint_t>( r ) );
|
||||
}
|
||||
|
||||
class UnicodeString {
|
||||
public:
|
||||
typedef std::vector<char32_t> data_buffer_t;
|
||||
|
@ -25,6 +35,15 @@ public:
|
|||
assign( src );
|
||||
}
|
||||
|
||||
explicit UnicodeString( UnicodeString const& other, int offset, int len = -1 )
|
||||
: _data() {
|
||||
_data.insert(
|
||||
_data.end(),
|
||||
other._data.begin() + offset,
|
||||
len > 0 ? other._data.begin() + offset + len : other._data.end()
|
||||
);
|
||||
}
|
||||
|
||||
explicit UnicodeString( char const* src )
|
||||
: _data() {
|
||||
assign( src );
|
||||
|
@ -87,6 +106,10 @@ public:
|
|||
return ( _data != other_._data );
|
||||
}
|
||||
|
||||
bool operator < ( UnicodeString const& other_ ) const {
|
||||
return std::lexicographical_compare(begin(), end(), other_.begin(), other_.end());
|
||||
}
|
||||
|
||||
UnicodeString& append( UnicodeString const& other ) {
|
||||
_data.insert( _data.end(), other._data.begin(), other._data.end() );
|
||||
return *this;
|
||||
|
@ -137,11 +160,13 @@ public:
|
|||
_data.clear();
|
||||
}
|
||||
|
||||
const char32_t& operator[]( size_t pos ) const {
|
||||
const char32_t& operator[]( int pos ) const {
|
||||
assert( ( pos >= 0 ) && ( pos < static_cast<int>( _data.size() ) ) );
|
||||
return _data[pos];
|
||||
}
|
||||
|
||||
char32_t& operator[]( size_t pos ) {
|
||||
char32_t& operator[]( int pos ) {
|
||||
assert( ( pos >= 0 ) && ( pos < static_cast<int>( _data.size() ) ) );
|
||||
return _data[pos];
|
||||
}
|
||||
|
||||
|
@ -152,6 +177,14 @@ public:
|
|||
);
|
||||
}
|
||||
|
||||
template <class BinaryPredicate>
|
||||
bool starts_with( data_buffer_t::const_iterator first_, data_buffer_t::const_iterator last_, BinaryPredicate&& pred ) const {
|
||||
return (
|
||||
( std::distance( first_, last_ ) <= length() )
|
||||
&& ( std::equal( first_, last_, _data.begin(), std::forward<BinaryPredicate>( pred ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
bool ends_with( data_buffer_t::const_iterator first_, data_buffer_t::const_iterator last_ ) const {
|
||||
int len( static_cast<int>( std::distance( first_, last_ ) ) );
|
||||
return (
|
||||
|
@ -183,6 +216,10 @@ public:
|
|||
iterator end( void ) {
|
||||
return ( _data.end() );
|
||||
}
|
||||
|
||||
char32_t back( void ) const {
|
||||
return ( _data.back() );
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
8
third-party/replxx/src/utf8string.hxx
generated
vendored
8
third-party/replxx/src/utf8string.hxx
generated
vendored
|
@ -68,7 +68,13 @@ public:
|
|||
}
|
||||
|
||||
bool operator != ( Utf8String const& other_ ) {
|
||||
return ( ( other_._len != _len ) || ( memcmp( other_._data.get(), _data.get(), _len ) != 0 ) );
|
||||
return (
|
||||
( other_._len != _len )
|
||||
|| (
|
||||
( _len != 0 )
|
||||
&& ( memcmp( other_._data.get(), _data.get(), _len ) != 0 )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
247
third-party/replxx/src/util.cxx
generated
vendored
247
third-party/replxx/src/util.cxx
generated
vendored
|
@ -5,149 +5,158 @@
|
|||
#include <wctype.h>
|
||||
|
||||
#include "util.hxx"
|
||||
#include "terminal.hxx"
|
||||
|
||||
#undef min
|
||||
|
||||
namespace replxx {
|
||||
|
||||
int mk_wcwidth( char32_t );
|
||||
|
||||
/**
|
||||
* Recompute widths of all characters in a char32_t buffer
|
||||
* @param text - input buffer of Unicode characters
|
||||
* @param widths - output buffer of character widths
|
||||
* @param charCount - number of characters in buffer
|
||||
*/
|
||||
void recompute_character_widths( char32_t const* text, char* widths, int charCount ) {
|
||||
for (int i = 0; i < charCount; ++i) {
|
||||
widths[i] = mk_wcwidth(text[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a new screen position given a starting position, screen width and
|
||||
* character count
|
||||
* @param x - initial x position (zero-based)
|
||||
* @param y - initial y position (zero-based)
|
||||
* @param screenColumns - screen column count
|
||||
* @param charCount - character positions to advance
|
||||
* @param xOut - returned x position (zero-based)
|
||||
* @param yOut - returned y position (zero-based)
|
||||
*/
|
||||
void calculate_screen_position(
|
||||
int x, int y, int screenColumns,
|
||||
int charCount, int& xOut, int& yOut
|
||||
) {
|
||||
xOut = x;
|
||||
yOut = y;
|
||||
int charsRemaining = charCount;
|
||||
while ( charsRemaining > 0 ) {
|
||||
int charsThisRow = ( ( x + charsRemaining ) < screenColumns )
|
||||
? charsRemaining
|
||||
: screenColumns - x;
|
||||
xOut = x + charsThisRow;
|
||||
yOut = y;
|
||||
charsRemaining -= charsThisRow;
|
||||
x = 0;
|
||||
++ y;
|
||||
}
|
||||
if ( xOut == screenColumns ) { // we have to special-case line wrap
|
||||
xOut = 0;
|
||||
++ yOut;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a column width using mk_wcswidth()
|
||||
* @param buf32 - text to calculate
|
||||
* @param len - length of text to calculate
|
||||
*/
|
||||
int calculate_displayed_length( char32_t const* buf32_, int size_ ) {
|
||||
int len( 0 );
|
||||
for ( int i( 0 ); i < size_; ++ i ) {
|
||||
char32_t c( buf32_[i] );
|
||||
int virtual_render( char32_t const* display_, int size_, int& x_, int& y_, int screenColumns_, int promptLen_, char32_t* rendered_, int* renderedSize_ ) {
|
||||
char32_t* out( rendered_ );
|
||||
int visibleCount( 0 );
|
||||
auto render = [&rendered_, &renderedSize_, &out, &visibleCount]( char32_t c_, bool visible_, bool renderAttributes_ = true ) {
|
||||
if ( rendered_ && renderedSize_ && renderAttributes_ ) {
|
||||
*out = c_;
|
||||
++ out;
|
||||
if ( visible_ ) {
|
||||
++ visibleCount;
|
||||
}
|
||||
}
|
||||
};
|
||||
bool wrapped( false );
|
||||
auto advance_cursor = [&x_, &y_, &screenColumns_, &wrapped]( int by_ = 1 ) {
|
||||
wrapped = false;
|
||||
x_ += by_;
|
||||
if ( x_ >= screenColumns_ ) {
|
||||
x_ = 0;
|
||||
++ y_;
|
||||
wrapped = true;
|
||||
}
|
||||
};
|
||||
bool const renderAttributes( !!tty::out );
|
||||
int pos( 0 );
|
||||
while ( pos < size_ ) {
|
||||
char32_t c( display_[pos] );
|
||||
if ( ( c == '\n' ) || ( c == '\r' ) ) {
|
||||
render( c, true );
|
||||
if ( ( c == '\n' ) && ! wrapped ) {
|
||||
++ y_;
|
||||
}
|
||||
x_ = promptLen_;
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
if ( c == '\b' ) {
|
||||
render( c, true );
|
||||
-- x_;
|
||||
if ( x_ < 0 ) {
|
||||
x_ = screenColumns_ - 1;
|
||||
-- y_;
|
||||
}
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
if ( c == '\033' ) {
|
||||
int escStart( i );
|
||||
++ i;
|
||||
if ( ( i < size_ ) && ( buf32_[i] != '[' ) ) {
|
||||
i = escStart;
|
||||
++ len;
|
||||
render( c, false, renderAttributes );
|
||||
++ pos;
|
||||
if ( pos >= size_ ) {
|
||||
advance_cursor( 2 );
|
||||
continue;
|
||||
}
|
||||
++ i;
|
||||
for ( ; i < size_; ++ i ) {
|
||||
c = buf32_[i];
|
||||
c = display_[pos];
|
||||
if ( c != '[' ) {
|
||||
advance_cursor( 2 );
|
||||
continue;
|
||||
}
|
||||
render( c, false, renderAttributes );
|
||||
++ pos;
|
||||
if ( pos >= size_ ) {
|
||||
advance_cursor( 3 );
|
||||
continue;
|
||||
}
|
||||
int codeLen( 0 );
|
||||
while ( pos < size_ ) {
|
||||
c = display_[pos];
|
||||
if ( ( c != ';' ) && ( ( c < '0' ) || ( c > '9' ) ) ) {
|
||||
break;
|
||||
}
|
||||
render( c, false, renderAttributes );
|
||||
++ codeLen;
|
||||
++ pos;
|
||||
}
|
||||
if ( ( i < size_ ) && ( buf32_[i] == 'm' ) ) {
|
||||
if ( pos >= size_ ) {
|
||||
continue;
|
||||
}
|
||||
i = escStart;
|
||||
len += 2;
|
||||
} else if ( is_control_code( c ) ) {
|
||||
len += 2;
|
||||
} else {
|
||||
int wcw( mk_wcwidth( c ) );
|
||||
if ( wcw < 0 ) {
|
||||
len = -1;
|
||||
break;
|
||||
c = display_[pos];
|
||||
if ( c != 'm' ) {
|
||||
advance_cursor( 3 + codeLen );
|
||||
continue;
|
||||
}
|
||||
len += wcw;
|
||||
render( c, false, renderAttributes );
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
if ( is_control_code( c ) ) {
|
||||
render( c, true );
|
||||
advance_cursor( 2 );
|
||||
++ pos;
|
||||
continue;
|
||||
}
|
||||
int wcw( mk_wcwidth( c ) );
|
||||
if ( wcw < 0 ) {
|
||||
break;
|
||||
}
|
||||
render( c, true );
|
||||
advance_cursor( wcw );
|
||||
++ pos;
|
||||
}
|
||||
return ( len );
|
||||
if ( rendered_ && renderedSize_ ) {
|
||||
*renderedSize_ = out - rendered_;
|
||||
}
|
||||
return ( visibleCount );
|
||||
}
|
||||
|
||||
char const* ansi_color( Replxx::Color color_ ) {
|
||||
static char const reset[] = "\033[0m";
|
||||
static char const black[] = "\033[0;22;30m";
|
||||
static char const red[] = "\033[0;22;31m";
|
||||
static char const green[] = "\033[0;22;32m";
|
||||
static char const brown[] = "\033[0;22;33m";
|
||||
static char const blue[] = "\033[0;22;34m";
|
||||
static char const magenta[] = "\033[0;22;35m";
|
||||
static char const cyan[] = "\033[0;22;36m";
|
||||
static char const lightgray[] = "\033[0;22;37m";
|
||||
|
||||
int unsigned code( static_cast<int unsigned>( color_ ) );
|
||||
int unsigned fg( code & 0xFFu );
|
||||
int unsigned bg( ( code >> 8 ) & 0xFFu );
|
||||
char const* bold( ( code & color::BOLD ) != 0 ? ";1" : "" );
|
||||
char const* underline = ( ( code & color::UNDERLINE ) != 0 ? ";4" : "" );
|
||||
static int const MAX_COLOR_CODE_SIZE( 32 );
|
||||
static char colorBuffer[MAX_COLOR_CODE_SIZE];
|
||||
int pos( 0 );
|
||||
if ( ( code & static_cast<int unsigned>( Replxx::Color::DEFAULT ) ) != 0 ) {
|
||||
pos = snprintf( colorBuffer, MAX_COLOR_CODE_SIZE, "\033[0%s%sm", underline, bold );
|
||||
} else if ( fg <= static_cast<int unsigned>( Replxx::Color::LIGHTGRAY ) ) {
|
||||
pos = snprintf( colorBuffer, MAX_COLOR_CODE_SIZE, "\033[0;22;3%d%s%sm", fg, underline, bold );
|
||||
} else if ( fg <= static_cast<int unsigned>( Replxx::Color::WHITE ) ) {
|
||||
#ifdef _WIN32
|
||||
static bool const has256colorDefault( true );
|
||||
static bool const has256colorDefault( true );
|
||||
#else
|
||||
static bool const has256colorDefault( false );
|
||||
static bool const has256colorDefault( false );
|
||||
#endif
|
||||
static char const* TERM( getenv( "TERM" ) );
|
||||
static bool const has256color( TERM ? ( strstr( TERM, "256" ) != nullptr ) : has256colorDefault );
|
||||
static char const* gray = has256color ? "\033[0;1;90m" : "\033[0;1;30m";
|
||||
static char const* brightred = has256color ? "\033[0;1;91m" : "\033[0;1;31m";
|
||||
static char const* brightgreen = has256color ? "\033[0;1;92m" : "\033[0;1;32m";
|
||||
static char const* yellow = has256color ? "\033[0;1;93m" : "\033[0;1;33m";
|
||||
static char const* brightblue = has256color ? "\033[0;1;94m" : "\033[0;1;34m";
|
||||
static char const* brightmagenta = has256color ? "\033[0;1;95m" : "\033[0;1;35m";
|
||||
static char const* brightcyan = has256color ? "\033[0;1;96m" : "\033[0;1;36m";
|
||||
static char const* white = has256color ? "\033[0;1;97m" : "\033[0;1;37m";
|
||||
static char const error[] = "\033[101;1;33m";
|
||||
|
||||
char const* code( reset );
|
||||
switch ( color_ ) {
|
||||
case Replxx::Color::BLACK: code = black; break;
|
||||
case Replxx::Color::RED: code = red; break;
|
||||
case Replxx::Color::GREEN: code = green; break;
|
||||
case Replxx::Color::BROWN: code = brown; break;
|
||||
case Replxx::Color::BLUE: code = blue; break;
|
||||
case Replxx::Color::MAGENTA: code = magenta; break;
|
||||
case Replxx::Color::CYAN: code = cyan; break;
|
||||
case Replxx::Color::LIGHTGRAY: code = lightgray; break;
|
||||
case Replxx::Color::GRAY: code = gray; break;
|
||||
case Replxx::Color::BRIGHTRED: code = brightred; break;
|
||||
case Replxx::Color::BRIGHTGREEN: code = brightgreen; break;
|
||||
case Replxx::Color::YELLOW: code = yellow; break;
|
||||
case Replxx::Color::BRIGHTBLUE: code = brightblue; break;
|
||||
case Replxx::Color::BRIGHTMAGENTA: code = brightmagenta; break;
|
||||
case Replxx::Color::BRIGHTCYAN: code = brightcyan; break;
|
||||
case Replxx::Color::WHITE: code = white; break;
|
||||
case Replxx::Color::ERROR: code = error; break;
|
||||
case Replxx::Color::DEFAULT: code = reset; break;
|
||||
static char const* TERM( getenv( "TERM" ) );
|
||||
static bool const has256color( TERM ? ( strstr( TERM, "256" ) != nullptr ) : has256colorDefault );
|
||||
static char const* ansiEscapeCodeTemplate = has256color ? "\033[0;9%d%s%sm" : "\033[0;1;3%d%s%sm";
|
||||
pos = snprintf( colorBuffer, MAX_COLOR_CODE_SIZE, ansiEscapeCodeTemplate, fg - static_cast<int>( Replxx::Color::GRAY ), underline, bold );
|
||||
} else {
|
||||
pos = snprintf( colorBuffer, MAX_COLOR_CODE_SIZE, "\033[0;38;5;%d%s%sm", fg, underline, bold );
|
||||
}
|
||||
return ( code );
|
||||
if ( ( code & color::BACKGROUND_COLOR_SET ) == 0 ) {
|
||||
return colorBuffer;
|
||||
}
|
||||
if ( bg <= static_cast<int unsigned>( Replxx::Color::WHITE ) ) {
|
||||
if ( bg <= static_cast<int unsigned>( Replxx::Color::LIGHTGRAY ) ) {
|
||||
snprintf( colorBuffer + pos, MAX_COLOR_CODE_SIZE - pos, "\033[4%dm", bg );
|
||||
} else {
|
||||
snprintf( colorBuffer + pos, MAX_COLOR_CODE_SIZE - pos, "\033[10%dm", bg - static_cast<int>( Replxx::Color::GRAY ) );
|
||||
}
|
||||
} else {
|
||||
snprintf( colorBuffer + pos, MAX_COLOR_CODE_SIZE - pos, "\033[48;5;%dm", bg );
|
||||
}
|
||||
return colorBuffer;
|
||||
}
|
||||
|
||||
std::string now_ms_str( void ) {
|
||||
|
|
12
third-party/replxx/src/util.hxx
generated
vendored
12
third-party/replxx/src/util.hxx
generated
vendored
|
@ -5,6 +5,14 @@
|
|||
|
||||
namespace replxx {
|
||||
|
||||
namespace color {
|
||||
static int unsigned const RGB666 = 16u;
|
||||
static int unsigned const GRAYSCALE = 232u;
|
||||
static int unsigned const BOLD = 1u << 17u;
|
||||
static int unsigned const UNDERLINE = 1u << 18u;
|
||||
static int unsigned const BACKGROUND_COLOR_SET = 1u << 19u;
|
||||
}
|
||||
|
||||
inline bool is_control_code(char32_t testChar) {
|
||||
return (testChar < ' ') || // C0 controls
|
||||
(testChar >= 0x7F && testChar <= 0x9F); // DEL and C1 controls
|
||||
|
@ -14,9 +22,7 @@ inline char32_t control_to_human( char32_t key ) {
|
|||
return ( key < 27 ? ( key + 0x40 ) : ( key + 0x18 ) );
|
||||
}
|
||||
|
||||
void recompute_character_widths( char32_t const* text, char* widths, int charCount );
|
||||
void calculate_screen_position( int x, int y, int screenColumns, int charCount, int& xOut, int& yOut );
|
||||
int calculate_displayed_length( char32_t const* buf32, int size );
|
||||
int virtual_render( char32_t const*, int, int&, int&, int, int, char32_t* = nullptr, int* = nullptr );
|
||||
char const* ansi_color( Replxx::Color );
|
||||
std::string now_ms_str( void );
|
||||
|
||||
|
|
2
third-party/replxx/src/windows.cxx
generated
vendored
2
third-party/replxx/src/windows.cxx
generated
vendored
|
@ -113,7 +113,7 @@ int win_write( HANDLE out_, bool autoEscape_, char const* str_, int size_ ) {
|
|||
int toWrite( static_cast<int>( str_ - s ) );
|
||||
WriteConsoleA( out_, s, static_cast<DWORD>( toWrite ), &nWritten, nullptr );
|
||||
count += nWritten;
|
||||
if ( nWritten != toWrite ) {
|
||||
if ( static_cast<int>( nWritten ) != toWrite ) {
|
||||
s = str_ = nullptr;
|
||||
break;
|
||||
}
|
||||
|
|
1571
third-party/replxx/tests.py
generated
vendored
1571
third-party/replxx/tests.py
generated
vendored
File diff suppressed because it is too large
Load diff
|
@ -33,3 +33,5 @@ third-party/imgui:
|
|||
git: https://github.com/ocornut/imgui/tree/v1.89.2
|
||||
third-party/tree-sitter:
|
||||
git: https://github.com/tree-sitter/tree-sitter/tree/v0.20.8
|
||||
third-party/replxx:
|
||||
git: https://github.com/AmokHuginnsson/replxx/commit/1f149bfe20bf6e49c1afd4154eaf0032c8c2fda2
|
||||
|
|
Loading…
Reference in a new issue