pike.git / lib / modules / Stdio.pmod / Readline.pike

version» Context lines:

pike.git/lib/modules/Stdio.pmod/Readline.pike:1: - // $Id: Readline.pike,v 1.46 2003/05/06 00:06:03 nilsson Exp $ + // $Id: Readline.pike,v 1.47 2003/06/26 23:06:03 nilsson Exp $   #pike __REAL_VERSION__      class OutputController   { -  static private object(Stdio.File) outfd; -  static private object(Stdio.Terminfo.Termcap) term; +  static private .File outfd; +  static private .Terminfo.Termcap term;    static private int xpos = 0, columns = 0;    static private mapping oldattrs = 0;      #define BLINK 1   #define BOLD 2   #define DIM 4   #define REVERSE 8   #define ITALIC 16   #define STANDOUT 32   #define UNDERLINE 64
pike.git/lib/modules/Stdio.pmod/Readline.pike:27:    "dim":DIM,    "reverse":REVERSE,    "italic":ITALIC,    "standout":STANDOUT,    "underline":UNDERLINE    ]), atts));    }       static void low_set_attributes(int mask, int val, int|void temp)    { -  int i, remv = mask & selected_attributes & ~val; +  int remv = mask & selected_attributes & ~val;    string s = "";       if(remv & 15) {    s += term->put("me")||"";    needed_attributes |= selected_attributes;    active_attributes = 0;    }    if(temp) {    needed_attributes |= remv;    } else {    selected_attributes &= ~remv;    needed_attributes &= ~remv;    }    active_attributes &= ~remv; -  for(i=0; remv; i++) +  for(int i=0; remv; i++)    if(remv & (1<<i)) {    string cap = ({0,0,0,0,"ZR","se","ue"})[i];    if(cap && (cap = term->put(cap)))    s += cap;    remv &= ~(1<<i);    }    if(sizeof(s))    outfd->write(s);    int add = mask & val & ~selected_attributes;    selected_attributes |= add;
pike.git/lib/modules/Stdio.pmod/Readline.pike:80:    if(cap && (cap = term->put(cap))) {    s += cap;    active_attributes |= i;    }    add &= ~(1<<i);    }    if(sizeof(s))    outfd->write(s);    }    +  //! Set the provided attributes to on.    void turn_on(string ... atts)    {    low_set_attributes(low_attribute_mask(atts), ~0);    }    -  +  //! Set the provided attributes to off.    void turn_off(string ... atts)    {    low_set_attributes(low_attribute_mask(atts), 0);    }    -  +  //!    void disable()    {    catch{    if(oldattrs)    outfd->tcsetattr((["OPOST":0,"ONLCR":0,"OCRNL":0,    "OLCUC":0,"OFILL":0,"OFDEL":0,    "ONLRET":0,"ONOCR":0])&oldattrs);    else    outfd->tcsetattr((["OPOST":1]));    };    }    -  +  //!    void enable()    {    if(term->put("cr") && term->put("do"))    catch { outfd->tcsetattr((["OPOST":0])); };    else    catch { outfd->tcsetattr((["OPOST":1,"ONLCR":1,"OCRNL":0,"OLCUC":0,    "OFILL":1,"OFDEL":0,"ONLRET":0,"ONOCR":0]));};    }    -  void destroy() +  static void destroy()    {    disable();    }    -  +  //! Check the terminal width. +  //! @seealso +  //! @[get_number_of_columns]    void check_columns()    {    catch {    int c = outfd->tcgetattr()->columns;    if(c)    columns = c;    };    if(!columns)    columns = term->tgetnum("co") || 80;    }    -  +  //! Returns the width of the terminal. +  //! @note +  //! Does not check the width of the terminal. +  //! @seealso +  //! @[check_columns]    int get_number_of_columns()    {    return columns;    }       static string escapify(string s, void|int hide)    {   #if 1    s=replace(s,    ({
pike.git/lib/modules/Stdio.pmod/Readline.pike:183:    static int width(string s)    {    return sizeof(s);    }       static int escapified_width(string s)    {    return width(escapify(s));    }    +  //!    void low_write(string s, void|int word_break)    {    int n = width(s);    if(!n)    return;       if(needed_attributes)    low_enable_attributes();      // werror("low_write(%O)\n",s);
pike.git/lib/modules/Stdio.pmod/Readline.pike:235:    }    }    string le;    if(n>0) {    outfd->write(s);    xpos += n;    } else if(xpos==0 && term->tgetflag("am") && (le=term->put("le")))    outfd->write(" "+le);    }    +  //!    void write(string s,void|int word_break,void|int hide)    {    low_write(escapify(s,hide),word_break);    }    -  +  //!    void low_move_downward(int n)    {    if(n<=0)    return;    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    outfd->write(term->put("DO", n) || (term->put("do")||"")*n);    }    -  +  //!    void low_move_upward(int n)    {    if(n<=0)    return;    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    outfd->write(term->put("UP", n) || (term->put("up")||"")*n);    }    -  +  //!    void low_move_forward(int n)    {    if(n<=0)    return;    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    if(xpos+n<columns) {    outfd->write(term->put("RI", n) ||    (term->put("nd")||term->put("ri")||"")*n);    xpos += n;
pike.git/lib/modules/Stdio.pmod/Readline.pike:279:    int l = (xpos+n)/columns;    low_move_downward(l);    n -= l*columns;    if(n<0)    low_move_backward(-n);    else if(n>0)    low_move_forward(n);    }    }    +  //!    void low_move_backward(int n)    {    if(n<=0)    return;    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    if(xpos-n>=0) {    outfd->write(term->put("LE", n) || (term->put("le")||"")*n);    xpos -= n;    } else {    int l = 1+(n-xpos-1)/columns;    low_move_upward(l);    n -= l*columns;    if(n<0)    low_move_forward(-n);    else if(n>0)    low_move_backward(n);    }    }    -  +  //!    void low_erase(int n)    {    string e = term->put("ec", n);    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    if (e)    outfd->write(e);    else    {    low_write(" "*n);    low_move_backward(n);    }    }    -  +  //!    void move_forward(string s)    {    low_move_forward(escapified_width(s));    }    -  +  //!    void move_backward(string s)    {    low_move_backward(escapified_width(s));    }    -  +  //!    void erase(string s)    {    low_erase(escapified_width(s));    }    -  +  //!    void newline()    {    string cr = term->put("cr"), down = term->put("do");    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    if(cr && down)    outfd->write(cr+down);    else    // In this case we have ONLCR (hopefully)    outfd->write("\n");    xpos = 0;    }    -  +  //!    void bol()    {    if(active_attributes && !term->tgetflag("ms"))    low_disable_attributes();    outfd->write(term->put("cr")||"");    xpos = 0;    }    -  +  //!    void clear(int|void partial)    {    string s;    if(active_attributes)    low_disable_attributes();    if(!partial && (s = term->put("cl"))) {    outfd->write(s);    xpos = 0;    return;    }    if(!partial) {    outfd->write(term->put("ho")||term->put("cm", 0, 0)||"");    xpos = 0;    }    outfd->write(term->put("cd")||"");    }    -  +  //!    void beep()    {    outfd->write(term->put("bl")||"");    }    -  void create(Stdio.File|void _outfd, -  Stdio.Terminfo.Termcap|string|void _term) +  //! +  void create(.File|void _outfd, +  .Terminfo.Termcap|string|void _term)    { -  outfd = _outfd || Stdio.File("stdout"); +  outfd = _outfd || .stdout;    term = objectp(_term)? _term : .Terminfo.getTerm(_term);    catch { oldattrs = outfd->tcgetattr(); };    check_columns();    } -  +    }      class InputController   {    static private object infd, term;    static private int enabled = -1;    static private function(:int) close_callback = 0;    static private string prefix="";    static private mapping(int:function|mapping(string:function)) bindings=([]);    static private function grab_binding = 0;    static private mapping oldattrs = 0;       int dumb=0;    -  void destroy() +  static void destroy()    {    catch{ infd->set_blocking(); };    if(dumb)    return;    catch{ infd->tcsetattr((["ECHO":1,"ICANON":1])); };    catch{ if(oldattrs) infd->tcsetattr((["ECHO":0,"ICANON":0,"VEOF":0,    "VEOL":0,"VLNEXT":0])&oldattrs); };    }       static private string process_input(string s)
pike.git/lib/modules/Stdio.pmod/Readline.pike:457:    s = prefix+s;    prefix = "";    }    prefix = process_input(s);    }       static private void close_cb()    {    if (close_callback && close_callback())    return; -  destruct(this_object()); +  destruct(this);    }       static private int set_enabled(int e)    {    if (e != enabled)    {    enabled = e;    if (enabled)    {    string oldprefix = prefix;
pike.git/lib/modules/Stdio.pmod/Readline.pike:480:    infd->set_nonblocking(read_cb, 0, close_cb);    }    else    infd->set_blocking();    return !enabled;    }    else    return enabled;    }    +  //!    int isenabled()    {    return enabled;    }    -  +  //!    int enable(int ... e)    {    if (sizeof(e))    return set_enabled(!!e[0]);    else    return set_enabled(1);    }    -  +  //!    int disable()    {    return set_enabled(0);    }    -  +  //!    int run_blocking()    {    disable();    string data = prefix;    prefix = "";    enabled = 1;    for (;;)    {    prefix = process_input(data);    if (!enabled)    return 0;    data = prefix+infd->read(1024, 1);    prefix = "";    if(!data || !sizeof(data)) {    disable();    return -1;    }    }    }    -  +  //!    void set_close_callback(function (:int) ccb)    {    close_callback = ccb;    }    -  +  //! Clears the bindings.    void nullbindings()    {    bindings = ([]);    }    -  +  //!    void grabnextkey(function g)    {    if(functionp(g))    grab_binding = g;    }    -  +  //!    function bindstr(string str, function f)    {    function oldf = 0;    if (mappingp(f))    f = 0; // Paranoia    switch (sizeof(str||""))    {    case 0:    break;    case 1:
pike.git/lib/modules/Stdio.pmod/Readline.pike:579:    if (!sizeof(bindings[str[0]]))    m_delete(bindings, str[0]);    else if(sizeof(bindings[str[0]])==1 && bindings[str[0]][str[0..0]])    bindings[str[0]] = bindings[str[0]][str[0..0]];    }    break;    }    return oldf;    }    +  //!    function unbindstr(string str)    {    return bindstr(str, 0);    }    -  +  //!    function getbindingstr(string str)    {    switch (sizeof(str||""))    {    case 0:    return 0;    case 1:    return mappingp(bindings[str[0]])?    bindings[str[0]][str] : bindings[str[0]];    default:    return mappingp(bindings[str[0]]) && bindings[str[0]][str];    }    }    -  +  //!    function bindtc(string cap, function f)    {    return bindstr(term->tgetstr(cap), f);    }    -  +  //!    function unbindtc(string cap)    {    return unbindstr(term->tgetstr(cap));    }    -  +  //!    function getbindingtc(string cap)    {    return getbindingstr(term->tgetstr(cap));    }    -  +  //!    string parsekey(string k)    {    if (k[..1]=="\\!")    k = term->tgetstr(k[2..]);    else for(int i=0; i<sizeof(k); i++)    switch(k[i])    {    case '\\':    if(i<sizeof(k)-1)    switch(k[i+1]) {
pike.git/lib/modules/Stdio.pmod/Readline.pike:671:    }    break;    case '^':    if(i<sizeof(k)-1 && k[i+1]>='?' && k[i+1]<='_')    k = k[..i-1]+(k[i+1]=='?'? "\177":sprintf("%c",k[i+1]-'@'))+k[i+2..];    break;    }    return k;    }    +  //!    function bind(string k, function f)    {    return bindstr(parsekey(k), f);    }    -  +  //!    function unbind(string k)    {    return unbindstr(parsekey(k));    }    -  +  //!    function getbinding(string k, string cap)    {    return getbindingstr(parsekey(k));    }    -  +  //!    mapping(string:function) getbindings()    {    mapping(int:function) bb = bindings-Array.filter(bindings, mappingp);    return `|(mkmapping(Array.map(indices(bb), lambda(int n) {    return sprintf("%c", n);    }), values(bb)),    @Array.filter(values(bindings), mappingp));    }    -  +  //!    void create(object|void _infd, object|string|void _term)    { -  infd = _infd || Stdio.File("stdin"); +  infd = _infd || .stdin;    term = objectp(_term)? _term : .Terminfo.getTerm(_term);    disable();    if(search(term->aliases, "dumb")>=0) {    // Dumb terminal. Don't try anything fancy.    dumb = 1;    return;    }    catch { oldattrs = infd->tcgetattr(); };    if(catch { infd->tcsetattr((["ECHO":0])); }) {    // If echo can't be disabled, Readline won't work very well.
pike.git/lib/modules/Stdio.pmod/Readline.pike:724:    }      }      class DefaultEditKeys   {    static private multiset word_break_chars =    mkmultiset("\t \n\r/*?_-.[]~&;\!#$%^(){}<>\"'`"/"");    static object _readline;    +  //!    void self_insert_command(string str)    {    _readline->insert(str, _readline->getcursorpos());    }    -  +  //!    void quoted_insert()    {    _readline->get_input_controller()->grabnextkey(self_insert_command);    }    -  +  //!    void newline()    {    _readline->newline();    }    -  +  //!    void up_history()    {    _readline->delta_history(-1);    }    -  +  //!    void down_history()    {    _readline->delta_history(1);    }    -  +  //!    void backward_delete_char()    {    int p = _readline->getcursorpos();    _readline->delete(p-1,p);    }    -  +  //!    void delete_char_or_eof()    {    int p = _readline->getcursorpos();    if (p<sizeof(_readline->gettext()))    _readline->delete(p,p+1);    else if(!sizeof(_readline->gettext()))    _readline->eof();    }    -  +  //!    void forward_char()    {    _readline->setcursorpos(_readline->getcursorpos()+1);    }    -  +  //!    void backward_char()    {    _readline->setcursorpos(_readline->getcursorpos()-1);    }    -  +  //!    void beginning_of_line()    {    _readline->setcursorpos(0);    }    -  +  //!    void end_of_line()    {    _readline->setcursorpos(sizeof(_readline->gettext()));    }    -  +  //!    void transpose_chars()    {    int p = _readline->getcursorpos();    if (p<0 || p>=sizeof(_readline->gettext()))    return;    string c = _readline->gettext()[p-1..p];    _readline->delete(p-1, p+1);    _readline->insert(reverse(c), p-1);    }   
pike.git/lib/modules/Stdio.pmod/Readline.pike:810:    p++;    if(p >= sizeof(line)) {    _readline->setcursorpos(p);    return ({ 0, 0 });    }    ep = forward_find_word();    _readline->delete(p, ep);    return ({ line[p..ep-1], p });    }    +  //!    void capitalize_word()    {    [string word, string pos]= find_word_to_manipulate();    if(word)    _readline->insert(String.capitalize(lower_case(word)), pos);    }    -  +  //!    void upcase_word()    {    [string word, string pos]= find_word_to_manipulate();    if(word)    _readline->insert(upper_case(word), pos);    }    -  +  //!    void downcase_word()    {    [string word, string pos]= find_word_to_manipulate();    if(word)    _readline->insert(lower_case(word), pos);    }       static int forward_find_word()    {    int p, n;
pike.git/lib/modules/Stdio.pmod/Readline.pike:859:    // find first "non break char"    p--;    for(;p >= 0; p--)    if(word_break_chars[ line[p..p] ]) {    p++; // We want to be one char before the break char.    break;    }    return p;    }    +  //!    void forward_word()    {    _readline->setcursorpos(forward_find_word());    }    -  +  //!    void backward_word()    {    _readline->setcursorpos(backward_find_word());    }    -  +  //!    void kill_word()    {    _readline->kill(_readline->getcursorpos(), forward_find_word());    }    -  +  //!    void backward_kill_word()    {    int sp = backward_find_word();    int ep = _readline->getcursorpos();    if((ep - sp) == 0)    sp--;    _readline->kill(sp, ep);    }    -  +  //!    void kill_line()    {    _readline->kill(_readline->getcursorpos(), sizeof(_readline->gettext()));    }    -  +  //!    void kill_whole_line()    {    _readline->kill(0, sizeof(_readline->gettext()));    }    -  +  //!    void yank()    {    _readline->setmark(_readline->getcursorpos());    _readline->insert(_readline->kill_ring_yank(),_readline->getcursorpos());    }    -  +  //!    void kill_ring_save()    {    _readline->add_to_kill_ring(_readline->region());    }    -  +  //!    void kill_region()    {    _readline->kill(@_readline->pointmark());    }    -  +  //!    void set_mark()    {    _readline->setmark(_readline->getcursorpos());    }    -  +  //!    void swap_mark_and_point()    {    int p=_readline->getcursorpos();    _readline->setcursorpos(_readline->getmark());    _readline->setmark(p);    }    -  +  //!    void redisplay()    {    _readline->redisplay(0);    }    -  +  //!    void clear_screen()    {    _readline->redisplay(1);    }       static array(array(string|function)) default_bindings = ({    ({ "^[[A", up_history }),    ({ "^[[B", down_history }),    ({ "^[[C", forward_char }),    ({ "^[[D", backward_char }),
pike.git/lib/modules/Stdio.pmod/Readline.pike:979:    ({ "^W", kill_region }),    ({ "^Y", yank }),    ({ "^?", backward_delete_char }),    ({ "\\!ku", up_history }),    ({ "\\!kd", down_history }),    ({ "\\!kr", forward_char }),    ({ "\\!kl", backward_char }),    ({ "^X^X", swap_mark_and_point }),    });    +  //!    static void set_default_bindings()    {    object ic = _readline->get_input_controller();    ic->nullbindings();    for(int i=' '; i<'\177'; i++)    ic->bindstr(sprintf("%c", i), self_insert_command);    for(int i='\240'; i<='\377'; i++)    ic->bindstr(sprintf("%c", i), self_insert_command);       if(ic->dumb) {    ic->bind("^J", newline);    return;    }       foreach(default_bindings, array(string|function) b)    ic->bind(@b);    }    -  +  //!    void create(object readline)    {    _readline = readline;    set_default_bindings();    }      }      class History   {    static private array(string) historylist;    static private mapping(int:string) historykeep=([]);    static private int minhistory, maxhistory, historynum;    -  +  //!    string encode()    {    return historylist*"\n";    }    -  +  //!    int get_history_num()    {    return historynum;    }    -  +  //!    string history(int n, string text)    {    if (n<minhistory)    n = minhistory;    else if (n-minhistory>=sizeof(historylist))    n = sizeof(historylist)+minhistory-1;    if(text != historylist[historynum-minhistory]) {    if(!historykeep[historynum])    historykeep[historynum] = historylist[historynum-minhistory];    historylist[historynum-minhistory]=text;    }    return historylist[(historynum=n)-minhistory];    }    -  +  //!    void initline()    {    if (sizeof(historylist)==0 || historylist[-1]!="") {    historylist += ({ "" });    if (maxhistory && sizeof(historylist)>maxhistory)    {    int n = sizeof(historylist)-maxhistory;    historylist = historylist[n..];    minhistory += n;    }    }    historynum = sizeof(historylist)-1+minhistory;    historykeep = ([]);    }    -  +  //!    void finishline(string text)    {    foreach(indices(historykeep), int n)    historylist[n-minhistory]=historykeep[n];    historykeep = ([]);    historylist[-1] = text;    if(sizeof(historylist)>1 && historylist[-2]==historylist[-1])    historylist = historylist[..sizeof(historylist)-2];    }    -  +  //!    void set_max_history(int maxhist)    {    maxhistory = maxhist;    }    -  +  //!    void create(int maxhist, void|array(string) hist)    {    historylist = hist || ({ "" });    minhistory = historynum = 0;    maxhistory = maxhist;    } -  +    }         static private OutputController output_controller;   static private InputController input_controller;   static private string prompt="";   static private array(string) prompt_attrs=0;   static private string text="", readtext;   static private function(string:void) newline_func;   static private int cursorpos = 0;
pike.git/lib/modules/Stdio.pmod/Readline.pike:1532:    historyobj = History(hist);   }      //! @fixme   //! Document this function   History get_history()   {    return historyobj;   }    + static void destroy() + { +  if(input_controller) +  destruct(input_controller); +  if(output_controller) +  destruct(output_controller); + } +    //! Creates a Readline object, that takes input from @[infd] and has output   //! on @[outfd].   //!   //! @param infd - //! Defaults to @[Stdio.stdout]. + //! Defaults to @[Stdio.stdin].   //!   //! @param interm   //! Defaults to @[Stdio.Terminfo.getTerm()].   //!   //! @param outfd   //! Defaults to @[infd], unless @[infd] is 0, in which case   //! @[outfd] defaults to @[Stdio.stdout].   //!   //! @param outterm   //! Defaults to @[interm].   void create(object|void infd, object|string|void interm,    object|void outfd, object|string|void outterm)   { -  +  atexit(destroy);    output_controller = OutputController(outfd || infd, outterm || interm);    input_controller = InputController(infd, interm); -  DefaultEditKeys(this_object()); +  DefaultEditKeys(this);   } -  - // compatibility - void destroy() {} +