input.cpp
algorithm
cstddef
cstdint
functional
sstream
string
utility
vector
ftxui/component/component.hpp
ftxui/component/component_base.hpp
ftxui/component/component_options.hpp
ftxui/component/event.hpp
ftxui/component/mouse.hpp
ftxui/component/screen_interactive.hpp
ftxui/dom/elements.hpp
ftxui/screen/box.hpp
ftxui/screen/string.hpp
ftxui/screen/string_internal.hpp
ftxui/screen/util.hpp
ftxui/util/ref.hpp
ftxui/component/animation.hpp
ftxui/component/captured_mouse.hpp
ftxui/component/component.hpp
ftxui/component/component_base.hpp
ftxui/component/component_options.hpp
ftxui/component/event.hpp
ftxui/component/mouse.hpp
ftxui/component/receiver.hpp
ftxui/component/screen_interactive.hpp
ftxui/component/task.hpp
ftxui/dom/canvas.hpp
ftxui/dom/deprecated.hpp
ftxui/dom/direction.hpp
ftxui/dom/elements.hpp
ftxui/dom/flexbox_config.hpp
ftxui/dom/linear_gradient.hpp
ftxui/dom/node.hpp
ftxui/dom/requirement.hpp
ftxui/dom/selection.hpp
ftxui/screen/box.hpp
ftxui/screen/color.hpp
ftxui/screen/image.hpp
ftxui/screen/pixel.hpp
ftxui/screen/screen.hpp
ftxui/screen/string.hpp
ftxui/screen/terminal.hpp
ftxui/util/autoreset.hpp
ftxui/util/ref.hpp
src/ftxui/component/input.cpp
ftxui/screen/string_internal.hpp
ftxui/screen/util.hpp
algorithm
atomic
chrono
condition_variable
cstddef
cstdint
ftxui/dom/take_any_args.hpp
functional
memory
mutex
optional
queue
sstream
string
thread
unordered_map
utility
variant
vector
ftxui

    //Copyright2022ArthurSonzogni.Allrightsreserved.
    //UseofthissourcecodeisgovernedbytheMITlicensethatcanbefoundin
    //theLICENSEfile.
    #include<algorithm>//formax,min
    #include<cstddef>//forsize_t
    #include<cstdint>//foruint32_t
    #include<functional>//forfunction
    #include<sstream>//forbasic_istream,stringstream
    #include<string>//forstring,basic_string,operator==,getline
    #include<utility>//formove
    #include<vector>//forvector

    #include"ftxui/component/component.hpp"//forMake,Input
    #include"ftxui/component/component_base.hpp"//forComponentBase
    #include"ftxui/component/component_options.hpp"//forInputOption
    #include"ftxui/component/event.hpp"//forEvent,Event::ArrowDown,Event::ArrowLeft,Event::ArrowLeftCtrl,Event::ArrowRight,Event::ArrowRightCtrl,Event::ArrowUp,Event::Backspace,Event::Delete,Event::End,Event::Home,Event::Return
    #include"ftxui/component/mouse.hpp"//forMouse,Mouse::Left,Mouse::Pressed
    #include"ftxui/component/screen_interactive.hpp"//forComponent
    #include"ftxui/dom/elements.hpp"//foroperator|,reflect,text,Element,xflex,hbox,Elements,frame,operator|=,vbox,focus,focusCursorBarBlinking,select
    #include"ftxui/screen/box.hpp"//forBox
    #include"ftxui/screen/string.hpp"//forstring_width
    #include"ftxui/screen/string_internal.hpp"//forGlyphNext,GlyphPrevious,WordBreakProperty,EatCodePoint,CodepointToWordBreakProperty,IsFullWidth,WordBreakProperty::ALetter,WordBreakProperty::CR,WordBreakProperty::Double_Quote,WordBreakProperty::Extend,WordBreakProperty::ExtendNumLet,WordBreakProperty::Format,WordBreakProperty::Hebrew_Letter,WordBreakProperty::Katakana,WordBreakProperty::LF,WordBreakProperty::MidLetter,WordBreakProperty::MidNum,WordBreakProperty::MidNumLet,WordBreakProperty::Newline,WordBreakProperty::Numeric,WordBreakProperty::Regional_Indicator,WordBreakProperty::Single_Quote,WordBreakProperty::WSegSpace,WordBreakProperty::ZWJ
    #include"ftxui/screen/util.hpp"//forclamp
    #include"ftxui/util/ref.hpp"//forStringRef,Ref

    namespaceftxui{

    namespace{

    std::vector<std::string>Split(conststd::string&input){
    std::vector<std::string>output;
    std::stringstreamss(input);
    std::stringline;
    while(std::getline(ss,line)){
    output.push_back(line);
    }
    if(input.back()=='\n'){
    output.emplace_back("");
    }
    returnoutput;
    }

    size_tGlyphWidth(conststd::string&input,size_titer){
    uint32_tucs=0;
    if(!EatCodePoint(input,iter,&iter,&ucs)){
    return0;
    }
    if(IsFullWidth(ucs)){
    return2;
    }
    return1;
    }

    boolIsWordCodePoint(uint32_tcodepoint){
    switch(CodepointToWordBreakProperty(codepoint)){
    caseWordBreakProperty::ALetter:
    caseWordBreakProperty::Hebrew_Letter:
    caseWordBreakProperty::Katakana:
    caseWordBreakProperty::Numeric:
    returntrue;

    caseWordBreakProperty::CR:
    caseWordBreakProperty::Double_Quote:
    caseWordBreakProperty::LF:
    caseWordBreakProperty::MidLetter:
    caseWordBreakProperty::MidNum:
    caseWordBreakProperty::MidNumLet:
    caseWordBreakProperty::Newline:
    caseWordBreakProperty::Single_Quote:
    caseWordBreakProperty::WSegSpace:
    //Unexpected/Unsure
    caseWordBreakProperty::Extend:
    caseWordBreakProperty::ExtendNumLet:
    caseWordBreakProperty::Format:
    caseWordBreakProperty::Regional_Indicator:
    caseWordBreakProperty::ZWJ:
    returnfalse;
    }
    returnfalse;//NOT_REACHED();
    }

    boolIsWordCharacter(conststd::string&input,size_titer){
    uint32_tucs=0;
    if(!EatCodePoint(input,iter,&iter,&ucs)){
    returnfalse;
    }

    returnIsWordCodePoint(ucs);
    }

    //Aninputbox.Theusercantypetextintoit.
    classInputBase:publicComponentBase,publicInputOption{
    public:
    //NOLINTNEXTLINE
    InputBase(InputOptionoption):InputOption(std::move(option)){}

    private:
    //Componentimplementation:
    ElementOnRender()override{
    constboolis_focused=Focused();
    constautofocused=(!is_focused&&!hovered_)?nothing
    :insert()?focusCursorBarBlinking
    :focusCursorBlockBlinking;

    autotransform_func=
    transform?transform:InputOption::Default().transform;

    //placeholder.
    if(content->empty()){
    autoelement=text(placeholder())|xflex|frame;

    returntransform_func({
    std::move(element),hovered_,is_focused,
    true//placeholder
    })|
    focus|reflect(box_);
    }

    Elementselements;
    conststd::vector<std::string>lines=Split(*content);

    cursor_position()=util::clamp(cursor_position(),0,(int)content->size());

    //Findthelineandindexofthecursor.
    intcursor_line=0;
    intcursor_char_index=cursor_position();
    for(constauto&line:lines){
    if(cursor_char_index<=(int)line.size()){
    break;
    }

    cursor_char_index-=static_cast<int>(line.size()+1);
    cursor_line++;
    }

    if(lines.empty()){
    elements.push_back(text("")|focused);
    }

    elements.reserve(lines.size());
    for(size_ti=0;i<lines.size();++i){
    conststd::string&line=lines[i];

    //Thisisnotthecursorline.
    if(int(i)!=cursor_line){
    elements.push_back(Text(line));
    continue;
    }

    //Thecursorisattheendoftheline.
    if(cursor_char_index>=(int)line.size()){
    elements.push_back(hbox({
    Text(line),
    text("")|focused|reflect(cursor_box_),
    })|
    xflex);
    continue;
    }

    //Thecursorisonthisline.
    constintglyph_start=cursor_char_index;
    constintglyph_end=static_cast<int>(GlyphNext(line,glyph_start));
    conststd::stringpart_before_cursor=line.substr(0,glyph_start);
    conststd::stringpart_at_cursor=
    line.substr(glyph_start,glyph_end-glyph_start);
    conststd::stringpart_after_cursor=line.substr(glyph_end);
    autoelement=hbox({
    Text(part_before_cursor),
    Text(part_at_cursor)|focused|reflect(cursor_box_),
    Text(part_after_cursor),
    })|
    xflex;
    elements.push_back(element);
    }

    autoelement=vbox(std::move(elements),cursor_line)|frame;
    returntransform_func({
    std::move(element),hovered_,is_focused,
    false//placeholder
    })|
    xflex|reflect(box_);
    }

    ElementText(conststd::string&input){
    if(!password()){
    returntext(input);
    }

    std::stringout;
    out.reserve(10+input.size()*3/2);
    for(size_ti=0;i<input.size();++i){
    out+="•";
    }
    returntext(out);
    }

    boolHandleBackspace(){
    if(cursor_position()==0){
    returnfalse;
    }
    constsize_tstart=GlyphPrevious(content(),cursor_position());
    constsize_tend=cursor_position();
    content->erase(start,end-start);
    cursor_position()=static_cast<int>(start);
    on_change();
    returntrue;
    }

    boolDeleteImpl(){
    if(cursor_position()==(int)content->size()){
    returnfalse;
    }
    constsize_tstart=cursor_position();
    constsize_tend=GlyphNext(content(),cursor_position());
    content->erase(start,end-start);
    returntrue;
    }

    boolHandleDelete(){
    if(DeleteImpl()){
    on_change();
    returntrue;
    }
    returnfalse;
    }

    boolHandleArrowLeft(){
    if(cursor_position()==0){
    returnfalse;
    }

    cursor_position()=
    static_cast<int>(GlyphPrevious(content(),cursor_position()));
    returntrue;
    }

    boolHandleArrowRight(){
    if(cursor_position()==(int)content->size()){
    returnfalse;
    }

    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));
    returntrue;
    }

    size_tCursorColumn(){
    size_titer=cursor_position();
    intwidth=0;
    while(true){
    if(iter==0){
    break;
    }
    iter=GlyphPrevious(content(),iter);
    if(content()[iter]=='\n'){
    break;
    }
    width+=static_cast<int>(GlyphWidth(content(),iter));
    }
    returnwidth;
    }

    //Movethecursor`columns`ontheright,ifpossible.
    voidMoveCursorColumn(intcolumns){
    while(columns>0){
    if(cursor_position()==(int)content().size()||
    content()[cursor_position()]=='\n'){
    return;
    }

    columns-=static_cast<int>(GlyphWidth(content(),cursor_position()));
    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));
    }
    }

    boolHandleArrowUp(){
    if(cursor_position()==0){
    returnfalse;
    }

    constsize_tcolumns=CursorColumn();

    //Movecursoratthebeginningof2linesabove.
    while(true){
    if(cursor_position()==0){
    returntrue;
    }
    constsize_tprevious=GlyphPrevious(content(),cursor_position());
    if(content()[previous]=='\n'){
    break;
    }
    cursor_position()=static_cast<int>(previous);
    }
    cursor_position()=
    static_cast<int>(GlyphPrevious(content(),cursor_position()));
    while(true){
    if(cursor_position()==0){
    break;
    }
    constsize_tprevious=GlyphPrevious(content(),cursor_position());
    if(content()[previous]=='\n'){
    break;
    }
    cursor_position()=static_cast<int>(previous);
    }

    MoveCursorColumn(static_cast<int>(columns));
    returntrue;
    }

    boolHandleArrowDown(){
    if(cursor_position()==(int)content->size()){
    returnfalse;
    }

    constsize_tcolumns=CursorColumn();

    //Movecursoratthebeginningofthenextline
    while(true){
    if(content()[cursor_position()]=='\n'){
    break;
    }
    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));
    if(cursor_position()==(int)content().size()){
    returntrue;
    }
    }
    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));

    MoveCursorColumn(static_cast<int>(columns));
    returntrue;
    }

    boolHandleHome(){
    cursor_position()=0;
    returntrue;
    }

    boolHandleEnd(){
    cursor_position()=static_cast<int>(content->size());
    returntrue;
    }

    boolHandleReturn(){
    if(multiline()){
    HandleCharacter("\n");
    }
    on_enter();
    returntrue;
    }

    boolHandleCharacter(conststd::string&character){
    if(!insert()&&cursor_position()<(int)content->size()&&
    content()[cursor_position()]!='\n'){
    DeleteImpl();
    }
    content->insert(cursor_position(),character);
    cursor_position()+=static_cast<int>(character.size());
    on_change();
    returntrue;
    }

    boolOnEvent(Eventevent)override{
    cursor_position()=util::clamp(cursor_position(),0,(int)content->size());

    if(event==Event::Return){
    returnHandleReturn();
    }
    if(event.is_character()){
    returnHandleCharacter(event.character());
    }
    if(event.is_mouse()){
    returnHandleMouse(event);
    }
    if(event==Event::Backspace){
    returnHandleBackspace();
    }
    if(event==Event::Delete){
    returnHandleDelete();
    }
    if(event==Event::ArrowLeft){
    returnHandleArrowLeft();
    }
    if(event==Event::ArrowRight){
    returnHandleArrowRight();
    }
    if(event==Event::ArrowUp){
    returnHandleArrowUp();
    }
    if(event==Event::ArrowDown){
    returnHandleArrowDown();
    }
    if(event==Event::Home){
    returnHandleHome();
    }
    if(event==Event::End){
    returnHandleEnd();
    }
    if(event==Event::ArrowLeftCtrl){
    returnHandleLeftCtrl();
    }
    if(event==Event::ArrowRightCtrl){
    returnHandleRightCtrl();
    }
    if(event==Event::Insert){
    returnHandleInsert();
    }
    returnfalse;
    }

    boolHandleLeftCtrl(){
    if(cursor_position()==0){
    returnfalse;
    }

    //Moveleft,aslongasleftitnotaword.
    while(cursor_position()){
    constsize_tprevious=GlyphPrevious(content(),cursor_position());
    if(IsWordCharacter(content(),previous)){
    break;
    }
    cursor_position()=static_cast<int>(previous);
    }
    //Moveleft,aslongasleftisawordcharacter:
    while(cursor_position()){
    constsize_tprevious=GlyphPrevious(content(),cursor_position());
    if(!IsWordCharacter(content(),previous)){
    break;
    }
    cursor_position()=static_cast<int>(previous);
    }
    returntrue;
    }

    boolHandleRightCtrl(){
    if(cursor_position()==(int)content().size()){
    returnfalse;
    }

    //Moveright,untilenteringaword.
    while(cursor_position()<(int)content().size()){
    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));
    if(IsWordCharacter(content(),cursor_position())){
    break;
    }
    }
    //Moveright,aslongasrightisawordcharacter:
    while(cursor_position()<(int)content().size()){
    constsize_tnext=GlyphNext(content(),cursor_position());
    if(!IsWordCharacter(content(),cursor_position())){
    break;
    }
    cursor_position()=static_cast<int>(next);
    }

    returntrue;
    }

    boolHandleMouse(Eventevent){
    hovered_=box_.Contain(event.mouse().x,//
    event.mouse().y)&&
    CaptureMouse(event);
    if(!hovered_){
    returnfalse;
    }

    if(event.mouse().button!=Mouse::Left){
    returnfalse;
    }
    if(event.mouse().motion!=Mouse::Pressed){
    returnfalse;
    }

    TakeFocus();

    if(content->empty()){
    cursor_position()=0;
    returntrue;
    }

    //Findthelineandindexofthecursor.
    std::vector<std::string>lines=Split(*content);
    intcursor_line=0;
    intcursor_char_index=cursor_position();
    for(constauto&line:lines){
    if(cursor_char_index<=(int)line.size()){
    break;
    }

    cursor_char_index-=static_cast<int>(line.size()+1);
    cursor_line++;
    }
    constintcursor_column=
    string_width(lines[cursor_line].substr(0,cursor_char_index));

    intnew_cursor_column=cursor_column+event.mouse().x-cursor_box_.x_min;
    intnew_cursor_line=cursor_line+event.mouse().y-cursor_box_.y_min;

    //Fixthenewcursorposition:
    new_cursor_line=std::max(std::min(new_cursor_line,(int)lines.size()),0);

    conststd::stringempty_string;
    conststd::string&line=new_cursor_line<(int)lines.size()
    ?lines[new_cursor_line]
    :empty_string;
    new_cursor_column=util::clamp(new_cursor_column,0,string_width(line));

    if(new_cursor_column==cursor_column&&//
    new_cursor_line==cursor_line){
    returnfalse;
    }

    //Convertbackthenew_cursor_{line,column}towardcursor_position:
    cursor_position()=0;
    for(inti=0;i<new_cursor_line;++i){
    cursor_position()+=static_cast<int>(lines[i].size()+1);
    }
    while(new_cursor_column>0){
    new_cursor_column-=
    static_cast<int>(GlyphWidth(content(),cursor_position()));
    cursor_position()=
    static_cast<int>(GlyphNext(content(),cursor_position()));
    }

    on_change();
    returntrue;
    }

    boolHandleInsert(){
    insert()=!insert();
    returntrue;
    }

    boolFocusable()constfinal{returntrue;}

    boolhovered_=false;

    Boxbox_;
    Boxcursor_box_;
    };

    }//namespace

    ///@briefAninputboxforeditingtext.
    ///@paramoptionAdditionaloptionalparameters.
    ///@ingroupcomponent
    ///@seeInputBase
    ///
    ///###Example
    ///
    ///```cpp
    ///autoscreen=ScreenInteractive::FitComponent();
    ///std::stringcontent="";
    ///std::stringplaceholder="placeholder";
    ///Componentinput=Input({
    ///.content=&content,
    ///.placeholder=&placeholder,
    ///})
    ///screen.Loop(input);
    ///```
    ///
    ///###Output
    ///
    ///```bash
    ///placeholder
    ///```
    ComponentInput(InputOptionoption){
    returnMake<InputBase>(std::move(option));
    }

    ///@briefAninputboxforeditingtext.
    ///@paramcontentTheeditablecontent.
    ///@paramoptionAdditionaloptionalparameters.
    ///@ingroupcomponent
    ///@seeInputBase
    ///
    ///###Example
    ///
    ///```cpp
    ///autoscreen=ScreenInteractive::FitComponent();
    ///std::stringcontent="";
    ///std::stringplaceholder="placeholder";
    ///Componentinput=Input(content,{
    ///.placeholder=&placeholder,
    ///.password=true,
    ///})
    ///screen.Loop(input);
    ///```
    ///
    ///###Output
    ///
    ///```bash
    ///placeholder
    ///```
    ComponentInput(StringRefcontent,InputOptionoption){
    option.content=std::move(content);
    returnMake<InputBase>(std::move(option));
    }

    ///@briefAninputboxforeditingtext.
    ///@paramcontentTheeditablecontent.
    ///@paramoptionAdditionaloptionalparameters.
    ///@ingroupcomponent
    ///@seeInputBase
    ///
    ///###Example
    ///
    ///```cpp
    ///autoscreen=ScreenInteractive::FitComponent();
    ///std::stringcontent="";
    ///std::stringplaceholder="placeholder";
    ///Componentinput=Input(content,placeholder);
    ///screen.Loop(input);
    ///```
    ///
    ///###Output
    ///
    ///```bash
    ///placeholder
    ///```
    ComponentInput(StringRefcontent,StringRefplaceholder,InputOptionoption){
    option.content=std::move(content);
    option.placeholder=std::move(placeholder);
    returnMake<InputBase>(std::move(option));
    }

    }//namespaceftxui