fd37f52011-04-25Martin Stjernholm // $Id$
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
6c00e02001-10-23Martin Nilsson 
492a0d2003-07-19Martin Nilsson //!
425ec12003-07-23Henrik Grubbström (Grubba) //! @fixme //! Ought to have support for charset conversion.
f9322c1999-03-13Marcus Comstedt class OutputController {
9eaf1d2008-06-28Martin Nilsson  protected private .File outfd; protected private .Terminfo.Termcap term; protected private int xpos = 0, columns = 0; protected private mapping oldattrs = 0;
ff62d71999-03-23Marcus Comstedt 
69d8bc1999-06-22Marcus Comstedt #define BLINK 1 #define BOLD 2 #define DIM 4 #define REVERSE 8 #define ITALIC 16 #define STANDOUT 32 #define UNDERLINE 64
9eaf1d2008-06-28Martin Nilsson  protected private int selected_attributes = 0, needed_attributes = 0; protected private int active_attributes = 0;
69d8bc1999-06-22Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson  protected int low_attribute_mask(array(string) atts)
69d8bc1999-06-22Marcus Comstedt  { return `|(@rows(([ "blink":BLINK, "bold":BOLD, "dim":DIM, "reverse":REVERSE, "italic":ITALIC, "standout":STANDOUT, "underline":UNDERLINE ]), atts)); }
9eaf1d2008-06-28Martin Nilsson  protected void low_set_attributes(int mask, int val, int|void temp)
69d8bc1999-06-22Marcus Comstedt  {
56e4b02003-06-27Martin Nilsson  int remv = mask & selected_attributes & ~val;
69d8bc1999-06-22Marcus Comstedt  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;
56e4b02003-06-27Martin Nilsson  for(int i=0; remv; i++)
69d8bc1999-06-22Marcus Comstedt  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; needed_attributes |= add; }
9eaf1d2008-06-28Martin Nilsson  protected void low_disable_attributes()
69d8bc1999-06-22Marcus Comstedt  { low_set_attributes(active_attributes, 0, 1); }
9eaf1d2008-06-28Martin Nilsson  protected void low_enable_attributes()
69d8bc1999-06-22Marcus Comstedt  { int i, add = needed_attributes; string s = ""; needed_attributes &= ~add; for(i=0; add; i++) if(add & (1<<i)) { string cap = ({"mb","md","mh","mr","ZH","so","us"})[i]; if(cap && (cap = term->put(cap))) { s += cap; active_attributes |= i; } add &= ~(1<<i); } if(sizeof(s)) outfd->write(s); }
56e4b02003-06-27Martin Nilsson  //! Set the provided attributes to on.
69d8bc1999-06-22Marcus Comstedt  void turn_on(string ... atts) { low_set_attributes(low_attribute_mask(atts), ~0); }
56e4b02003-06-27Martin Nilsson  //! Set the provided attributes to off.
69d8bc1999-06-22Marcus Comstedt  void turn_off(string ... atts) { low_set_attributes(low_attribute_mask(atts), 0); }
56e4b02003-06-27Martin Nilsson  //!
ff62d71999-03-23Marcus Comstedt  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])); }; }
56e4b02003-06-27Martin Nilsson  //!
ff62d71999-03-23Marcus Comstedt  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]));}; }
9eaf1d2008-06-28Martin Nilsson  protected void destroy()
ff62d71999-03-23Marcus Comstedt  { disable(); }
f9322c1999-03-13Marcus Comstedt 
425ec12003-07-23Henrik Grubbström (Grubba)  //! Check and return the terminal width. //! //! @note //! In Pike 7.4 and earlier this function returned @expr{void@}. //!
56e4b02003-06-27Martin Nilsson  //! @seealso //! @[get_number_of_columns]
425ec12003-07-23Henrik Grubbström (Grubba)  int check_columns()
f9322c1999-03-13Marcus Comstedt  { catch { int c = outfd->tcgetattr()->columns; if(c) columns = c; }; if(!columns) columns = term->tgetnum("co") || 80;
425ec12003-07-23Henrik Grubbström (Grubba)  return columns;
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //! Returns the width of the terminal. //! @note //! Does not check the width of the terminal. //! @seealso //! @[check_columns]
f9322c1999-03-13Marcus Comstedt  int get_number_of_columns() { return columns; }
9eaf1d2008-06-28Martin Nilsson  protected string escapify(string s, void|int hide)
ec8a231999-04-29Fredrik Hübinette (Hubbe)  { #if 1 s=replace(s, ({ "\000","\001","\002","\003","\004","\005","\006","\007", "\010","\011","\012","\013","\014","\015","\016","\017",
0c06b31999-06-09Marcus Comstedt  "\020","\021","\022","\023","\024","\025","\026","\027", "\030","\031","\032","\033","\034","\035","\036","\037",
ec8a231999-04-29Fredrik Hübinette (Hubbe)  "\177", "\200","\201","\202","\203","\204","\205","\206","\207", "\210","\211","\212","\213","\214","\215","\216","\217", "\220","\221","\222","\223","\224","\225","\226","\227", "\230","\231","\232","\233","\234","\235","\236","\237", }), ({ "^@","^A","^B","^C","^D","^E","^F","^G", "^H","^I","^J","^K","^L","^M","^N","^O",
0c06b31999-06-09Marcus Comstedt  "^P","^Q","^R","^S","^T","^U","^V","^W", "^X","^Y","^Z","^[","^\\","^]","^^","^_",
ec8a231999-04-29Fredrik Hübinette (Hubbe)  "^?", "~@","~A","~B","~C","~D","~E","~F","~G", "~H","~I","~J","~K","~L","~M","~N","~O", "~P","~Q","~R","~S","~T","~U","~V","~W", "~X","~Y","~Z","~[","~\\","~]","~^","~_", }));
ead9722003-01-20Martin Nilsson  return hide ? "*"*sizeof(s) : s;
ec8a231999-04-29Fredrik Hübinette (Hubbe) #else
ead9722003-01-20Martin Nilsson  for(int i=0; i<sizeof(s); i++)
f9322c1999-03-13Marcus Comstedt  if(s[i]<' ') s = s[..i-1]+sprintf("^%c", s[i]+'@')+s[i+1..]; else if(s[i]==127) s = s[..i-1]+"^?"+s[i+1..]; else if(s[i]>=128 && s[i]<160) s = s[..i-1]+sprintf("~%c", s[i]-128+'@')+s[i+1..]; return s;
ec8a231999-04-29Fredrik Hübinette (Hubbe) #endif
f9322c1999-03-13Marcus Comstedt  }
ec8a231999-04-29Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson  protected int width(string s)
f9322c1999-03-13Marcus Comstedt  {
ead9722003-01-20Martin Nilsson  return sizeof(s);
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected int escapified_width(string s)
f9322c1999-03-13Marcus Comstedt  { return width(escapify(s)); }
eeec562008-12-08Henrik Grubbström (Grubba)  // FIXME: Ought to buffer output. // FIXME: Ought to support nonblocking output.
56e4b02003-06-27Martin Nilsson  //!
0c06b31999-06-09Marcus Comstedt  void low_write(string s, void|int word_break)
f9322c1999-03-13Marcus Comstedt  { int n = width(s); if(!n) return;
ec8a231999-04-29Fredrik Hübinette (Hubbe) 
69d8bc1999-06-22Marcus Comstedt  if(needed_attributes) low_enable_attributes();
ec8a231999-04-29Fredrik Hübinette (Hubbe) // werror("low_write(%O)\n",s); if(word_break) { while(xpos+n>=columns) { int l = columns-xpos; string line=s[..l-1]; int spos=search(reverse(line)," "); if(spos==-1) { outfd->write(line);
f2bda92009-02-10Martin Stjernholm  xpos+=l;
ec8a231999-04-29Fredrik Hübinette (Hubbe)  }else{
ead9722003-01-20Martin Nilsson  l=sizeof(line)-spos;
ec8a231999-04-29Fredrik Hübinette (Hubbe)  outfd->write(line[..l-2]);
f2bda92009-02-10Martin Stjernholm  xpos+=l-1;
ec8a231999-04-29Fredrik Hübinette (Hubbe)  } s=s[l..]; n-=l;
20f7a71999-06-09Fredrik Hübinette (Hubbe)  if(xpos<columns || !term->tgetflag("am"))
ec8a231999-04-29Fredrik Hübinette (Hubbe)  outfd->write((term->put("cr")||"")+(term->put("do")||"\n")); xpos = 0; } }else{ while(xpos+n>=columns) { int l = columns-xpos; outfd->write(s[..l-1]); s=s[l..]; n-=l; xpos = 0; if(!term->tgetflag("am")) outfd->write((term->put("cr")||"")+(term->put("do")||"\n")); }
f9322c1999-03-13Marcus Comstedt  }
bd8e291999-03-23Marcus Comstedt  string le;
f9322c1999-03-13Marcus Comstedt  if(n>0) { outfd->write(s); xpos += n;
0c06b31999-06-09Marcus Comstedt  } else if(xpos==0 && term->tgetflag("am") && (le=term->put("le"))) outfd->write(" "+le);
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
0c06b31999-06-09Marcus Comstedt  void write(string s,void|int word_break,void|int hide)
f9322c1999-03-13Marcus Comstedt  {
0c06b31999-06-09Marcus Comstedt  low_write(escapify(s,hide),word_break);
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void low_move_downward(int n) { if(n<=0) return;
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  outfd->write(term->put("DO", n) || (term->put("do")||"")*n); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void low_move_upward(int n) { if(n<=0) return;
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  outfd->write(term->put("UP", n) || (term->put("up")||"")*n); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void low_move_forward(int n) { if(n<=0) return;
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  if(xpos+n<columns) {
81a6491999-10-21Marcus Comstedt  outfd->write(term->put("RI", n) || (term->put("nd")||term->put("ri")||"")*n);
f9322c1999-03-13Marcus Comstedt  xpos += n; } else { 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); } }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void low_move_backward(int n) { if(n<=0) return;
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  if(xpos-n>=0) {
13670d2003-10-09Henrik Grubbström (Grubba)  outfd->write(term->put("LE", n) || (term->put("le")||term->put("kb")||"\10")*n);
f9322c1999-03-13Marcus Comstedt  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); } }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void low_erase(int n) { string e = term->put("ec", n);
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  if (e) outfd->write(e); else { low_write(" "*n); low_move_backward(n); } }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void move_forward(string s) { low_move_forward(escapified_width(s)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void move_backward(string s) { low_move_backward(escapified_width(s)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void erase(string s) { low_erase(escapified_width(s)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void newline() {
a0efb42003-07-23Henrik Grubbström (Grubba)  string cr = term->put("cr"); // NOTE: Use "sf" in preference to "do" since "do" for "xterm" on HPUX // is "\33[B", which doesn't scroll when at the last line. string down = term->put("sf") || term->put("do");
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
ff62d71999-03-23Marcus Comstedt  if(cr && down) outfd->write(cr+down); else // In this case we have ONLCR (hopefully) outfd->write("\n");
f9322c1999-03-13Marcus Comstedt  xpos = 0; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void bol() {
69d8bc1999-06-22Marcus Comstedt  if(active_attributes && !term->tgetflag("ms")) low_disable_attributes();
ff62d71999-03-23Marcus Comstedt  outfd->write(term->put("cr")||"");
f9322c1999-03-13Marcus Comstedt  xpos = 0; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void clear(int|void partial) { string s;
69d8bc1999-06-22Marcus Comstedt  if(active_attributes) low_disable_attributes();
f9322c1999-03-13Marcus Comstedt  if(!partial && (s = term->put("cl"))) { outfd->write(s); xpos = 0; return; } if(!partial) {
ff62d71999-03-23Marcus Comstedt  outfd->write(term->put("ho")||term->put("cm", 0, 0)||"");
f9322c1999-03-13Marcus Comstedt  xpos = 0; }
ff62d71999-03-23Marcus Comstedt  outfd->write(term->put("cd")||"");
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
bbf84a1999-03-18Marcus Comstedt  void beep() { outfd->write(term->put("bl")||""); }
56e4b02003-06-27Martin Nilsson  //! void create(.File|void _outfd, .Terminfo.Termcap|string|void _term)
f9322c1999-03-13Marcus Comstedt  {
0e35122003-07-01Per Hedbor  outfd = _outfd || Stdio.File( "stdout", "w" );
f9322c1999-03-13Marcus Comstedt  term = objectp(_term)? _term : .Terminfo.getTerm(_term);
ff62d71999-03-23Marcus Comstedt  catch { oldattrs = outfd->tcgetattr(); };
f9322c1999-03-13Marcus Comstedt  check_columns(); } }
492a0d2003-07-19Martin Nilsson //!
425ec12003-07-23Henrik Grubbström (Grubba) //! @fixme //! Ought to have support for charset conversion.
f9322c1999-03-13Marcus Comstedt class InputController {
9eaf1d2008-06-28Martin Nilsson  protected private object infd, term; protected private int enabled = -1; protected private function(:int) close_callback = 0; protected private string prefix=""; protected private mapping(int:function|mapping(string:function)) bindings=([]); protected private function grab_binding = 0; protected private mapping oldattrs = 0;
f9322c1999-03-13Marcus Comstedt 
b090761999-06-11Marcus Comstedt  int dumb=0;
9eaf1d2008-06-28Martin Nilsson  protected void destroy()
f9322c1999-03-13Marcus Comstedt  { catch{ infd->set_blocking(); };
b090761999-06-11Marcus Comstedt  if(dumb) return;
ba064e1999-03-23Marcus Comstedt  catch{ infd->tcsetattr((["ECHO":1,"ICANON":1])); };
ff62d71999-03-23Marcus Comstedt  catch{ if(oldattrs) infd->tcsetattr((["ECHO":0,"ICANON":0,"VEOF":0, "VEOL":0,"VLNEXT":0])&oldattrs); };
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected private string process_input(string s)
f9322c1999-03-13Marcus Comstedt  { int i; for (i=0; i<sizeof(s); i++) { if (!enabled) return s[i..]; function|mapping(string:function) b = grab_binding || bindings[s[i]]; grab_binding = 0; if (!b) /* do nothing */; else if(mappingp(b)) { int ml = 0, l = sizeof(s)-i; string m; foreach (indices(b), string k) { if (sizeof(k)>l && k[..l-1]==s[i..]) /* Valid prefix, need more data */ return s[i..]; else if (sizeof(k) > ml && s[i..i+sizeof(k)-1] == k) { /* New longest match found */ ml = sizeof(m = k); } } if (ml) { i += ml-1; b[m](m); } } else b(s[i..i]); } return ""; }
9eaf1d2008-06-28Martin Nilsson  protected private void read_cb(mixed _, string s)
f9322c1999-03-13Marcus Comstedt  { if (!s || s=="") return; if (sizeof(prefix)) { s = prefix+s; prefix = ""; } prefix = process_input(s); }
9eaf1d2008-06-28Martin Nilsson  protected private void close_cb()
f9322c1999-03-13Marcus Comstedt  { if (close_callback && close_callback()) return;
56e4b02003-06-27Martin Nilsson  destruct(this);
f9322c1999-03-13Marcus Comstedt  }
9eaf1d2008-06-28Martin Nilsson  protected private int set_enabled(int e)
f9322c1999-03-13Marcus Comstedt  { if (e != enabled) { enabled = e; if (enabled) { string oldprefix = prefix; prefix = ""; prefix = process_input(oldprefix);
eeec562008-12-08Henrik Grubbström (Grubba)  if ((!infd->set_read_callback || !infd->set_close_callback) && infd->set_nonblocking)
9355492004-02-26Marcus Agehall  infd->set_nonblocking( read_cb, 0, close_cb ); else {
eeec562008-12-08Henrik Grubbström (Grubba)  // Avoid messing with the write callback if possible.
9355492004-02-26Marcus Agehall  infd->set_read_callback( read_cb ); infd->set_close_callback( close_cb ); }
f9322c1999-03-13Marcus Comstedt  }
eeec562008-12-08Henrik Grubbström (Grubba)  else if ((!infd->set_read_callback || !infd->set_close_callback) && infd->set_blocking)
f9322c1999-03-13Marcus Comstedt  infd->set_blocking();
eeec562008-12-08Henrik Grubbström (Grubba)  else { // Avoid messing with the write callback if possible. infd->set_read_callback(0); infd->set_close_callback(0); }
f9322c1999-03-13Marcus Comstedt  return !enabled; } else return enabled; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  int isenabled() { return enabled; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  int enable(int ... e) { if (sizeof(e)) return set_enabled(!!e[0]); else return set_enabled(1); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  int disable() { return set_enabled(0); }
56e4b02003-06-27Martin Nilsson  //!
74faa41999-03-23Marcus Comstedt  int run_blocking()
f9322c1999-03-13Marcus Comstedt  { disable(); string data = prefix; prefix = ""; enabled = 1; for (;;) { prefix = process_input(data); if (!enabled)
74faa41999-03-23Marcus Comstedt  return 0;
f9322c1999-03-13Marcus Comstedt  data = prefix+infd->read(1024, 1); prefix = "";
ba064e1999-03-23Marcus Comstedt  if(!data || !sizeof(data)) { disable();
74faa41999-03-23Marcus Comstedt  return -1;
ba064e1999-03-23Marcus Comstedt  }
f9322c1999-03-13Marcus Comstedt  } }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void set_close_callback(function (:int) ccb) { close_callback = ccb; }
56e4b02003-06-27Martin Nilsson  //! Clears the bindings.
f9322c1999-03-13Marcus Comstedt  void nullbindings() { bindings = ([]); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void grabnextkey(function g) { if(functionp(g)) grab_binding = g; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function bindstr(string str, function f) { function oldf = 0; if (mappingp(f)) f = 0; // Paranoia switch (sizeof(str||"")) { case 0: break; case 1: if (mappingp(bindings[str[0]])) { oldf = bindings[str[0]][str]; if (f) bindings[str[0]][str] = f; else m_delete(bindings[str[0]], str); } else { oldf = bindings[str[0]]; if (f) bindings[str[0]] = f; else m_delete(bindings, str[0]); } break; default: if (mappingp(bindings[str[0]])) oldf = bindings[str[0]][str]; else bindings[str[0]] = bindings[str[0]]? ([str[0..0]:bindings[str[0]]]) : ([]); if (f) bindings[str[0]][str] = f; else { m_delete(bindings[str[0]], str); 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; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function unbindstr(string str) { return bindstr(str, 0); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  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]; } }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function bindtc(string cap, function f) { return bindstr(term->tgetstr(cap), f); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function unbindtc(string cap) { return unbindstr(term->tgetstr(cap)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function getbindingtc(string cap) { return getbindingstr(term->tgetstr(cap)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  string parsekey(string k) { if (k[..1]=="\\!") k = term->tgetstr(k[2..]);
75b76a2004-11-02Henrik Grubbström (Grubba)  else if (k[..3]=="^[\\!") { // Kludge for symbolic meta in bind table. if (k = term->tgetstr(k[4..])) k = "\033" + k; } else for(int i=0; i<sizeof(k); i++)
f9322c1999-03-13Marcus Comstedt  switch(k[i]) { case '\\': if(i<sizeof(k)-1) switch(k[i+1]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': int n, l; if (2<sscanf(k[i+1..], "%o%n", n, l)) { n = k[i+1]-'0'; l = 1; } k = k[..i-1]+sprintf("%c", n)+k[i+1+l..]; break; case 'e': case 'E': k = k[..i-1]+"\033"+k[i+2..]; break; case 'n': k = k[..i-1]+"\n"+k[i+2..]; break; case 'r': k = k[..i-1]+"\r"+k[i+2..]; break; case 't': k = k[..i-1]+"\t"+k[i+2..]; break; case 'b': k = k[..i-1]+"\b"+k[i+2..]; break; case 'f': k = k[..i-1]+"\f"+k[i+2..]; break; default: k = k[..i-1]+k[i+1..]; break; } 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; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function bind(string k, function f) { return bindstr(parsekey(k), f); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function unbind(string k) { return unbindstr(parsekey(k)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  function getbinding(string k, string cap) { return getbindingstr(parsekey(k)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  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)); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void create(object|void _infd, object|string|void _term) {
0e35122003-07-01Per Hedbor  infd = _infd || Stdio.File( "stdin", "r" );
f9322c1999-03-13Marcus Comstedt  term = objectp(_term)? _term : .Terminfo.getTerm(_term); disable();
b090761999-06-11Marcus Comstedt  if(search(term->aliases, "dumb")>=0) { // Dumb terminal. Don't try anything fancy. dumb = 1; return; }
f9322c1999-03-13Marcus Comstedt  catch { oldattrs = infd->tcgetattr(); };
b090761999-06-11Marcus Comstedt  if(catch { infd->tcsetattr((["ECHO":0])); }) { // If echo can't be disabled, Readline won't work very well. // Go to dumb mode. dumb = 1; return; }
f9322c1999-03-13Marcus Comstedt  catch { infd->tcsetattr((["ECHO":0,"ICANON":0,"VMIN":1,"VTIME":0, "VLNEXT":0])); }; } }
492a0d2003-07-19Martin Nilsson //!
f9322c1999-03-13Marcus Comstedt class DefaultEditKeys {
9eaf1d2008-06-28Martin Nilsson  protected private multiset word_break_chars =
ff70fc2003-05-04Martin Nilsson  mkmultiset("\t \n\r/*?_-.[]~&;\!#$%^(){}<>\"'`"/"");
9eaf1d2008-06-28Martin Nilsson  protected object _readline;
f9322c1999-03-13Marcus Comstedt 
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void self_insert_command(string str) { _readline->insert(str, _readline->getcursorpos()); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void quoted_insert() { _readline->get_input_controller()->grabnextkey(self_insert_command); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void newline() { _readline->newline(); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void up_history() { _readline->delta_history(-1); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void down_history() { _readline->delta_history(1); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void backward_delete_char() { int p = _readline->getcursorpos(); _readline->delete(p-1,p); }
56e4b02003-06-27Martin Nilsson  //!
75b76a2004-11-02Henrik Grubbström (Grubba)  void delete_char() { int p = _readline->getcursorpos(); if (p<sizeof(_readline->gettext())) _readline->delete(p,p+1); } //!
f9322c1999-03-13Marcus Comstedt  void delete_char_or_eof() { int p = _readline->getcursorpos();
ead9722003-01-20Martin Nilsson  if (p<sizeof(_readline->gettext()))
f9322c1999-03-13Marcus Comstedt  _readline->delete(p,p+1);
ead9722003-01-20Martin Nilsson  else if(!sizeof(_readline->gettext()))
f9322c1999-03-13Marcus Comstedt  _readline->eof(); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void forward_char() { _readline->setcursorpos(_readline->getcursorpos()+1); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void backward_char() { _readline->setcursorpos(_readline->getcursorpos()-1); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void beginning_of_line() { _readline->setcursorpos(0); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void end_of_line() {
ead9722003-01-20Martin Nilsson  _readline->setcursorpos(sizeof(_readline->gettext()));
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void transpose_chars() { int p = _readline->getcursorpos();
ead9722003-01-20Martin Nilsson  if (p<0 || p>=sizeof(_readline->gettext()))
f9322c1999-03-13Marcus Comstedt  return; string c = _readline->gettext()[p-1..p]; _readline->delete(p-1, p+1); _readline->insert(reverse(c), p-1); }
9eaf1d2008-06-28Martin Nilsson  protected array find_word_to_manipulate()
400e7e1999-04-25David Hedbor  { int p = _readline->getcursorpos(); int ep; string line = _readline->gettext();
ead9722003-01-20Martin Nilsson  while(word_break_chars[ line[p..p] ] && p < sizeof(line))
400e7e1999-04-25David Hedbor  p++;
ead9722003-01-20Martin Nilsson  if(p >= sizeof(line)) {
400e7e1999-04-25David Hedbor  _readline->setcursorpos(p); return ({ 0, 0 }); } ep = forward_find_word(); _readline->delete(p, ep); return ({ line[p..ep-1], p }); }
56e4b02003-06-27Martin Nilsson  //!
400e7e1999-04-25David Hedbor  void capitalize_word() { [string word, string pos]= find_word_to_manipulate(); if(word) _readline->insert(String.capitalize(lower_case(word)), pos); }
56e4b02003-06-27Martin Nilsson  //!
f566a01999-04-25Marcus Comstedt  void upcase_word()
400e7e1999-04-25David Hedbor  { [string word, string pos]= find_word_to_manipulate(); if(word) _readline->insert(upper_case(word), pos); }
56e4b02003-06-27Martin Nilsson  //!
f566a01999-04-25Marcus Comstedt  void downcase_word()
400e7e1999-04-25David Hedbor  { [string word, string pos]= find_word_to_manipulate(); if(word) _readline->insert(lower_case(word), pos); }
56e4b02003-06-27Martin Nilsson 
9eaf1d2008-06-28Martin Nilsson  protected int forward_find_word()
53fa181999-04-02David Hedbor  { int p, n; string line = _readline->gettext(); for(p = _readline->getcursorpos(); p < sizeof(line); p++) { if(word_break_chars[ line[p..p] ]) { if(n) break; } else n = 1; } return p; }
9eaf1d2008-06-28Martin Nilsson  protected int backward_find_word()
53fa181999-04-02David Hedbor  {
400e7e1999-04-25David Hedbor  int p = _readline->getcursorpos()-1;
53fa181999-04-02David Hedbor  string line = _readline->gettext();
ead9722003-01-20Martin Nilsson  if(p >= sizeof(line)) p = sizeof(line) - 1;
400e7e1999-04-25David Hedbor  while(word_break_chars[ line[p..p] ] && p >= 0) // find first "non break char" p--; for(;p >= 0; p--)
53fa181999-04-02David Hedbor  if(word_break_chars[ line[p..p] ]) {
400e7e1999-04-25David Hedbor  p++; // We want to be one char before the break char. break; }
53fa181999-04-02David Hedbor  return p; }
56e4b02003-06-27Martin Nilsson  //!
53fa181999-04-02David Hedbor  void forward_word() { _readline->setcursorpos(forward_find_word()); }
56e4b02003-06-27Martin Nilsson  //!
53fa181999-04-02David Hedbor  void backward_word() { _readline->setcursorpos(backward_find_word()); }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void kill_word()
53fa181999-04-02David Hedbor  {
8e317d1999-06-06Mirar (Pontus Hagland)  _readline->kill(_readline->getcursorpos(), forward_find_word());
53fa181999-04-02David Hedbor  }
400e7e1999-04-25David Hedbor 
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void backward_kill_word()
53fa181999-04-02David Hedbor  {
400e7e1999-04-25David Hedbor  int sp = backward_find_word();
6dd2821999-04-02David Hedbor  int ep = _readline->getcursorpos(); if((ep - sp) == 0) sp--;
8e317d1999-06-06Mirar (Pontus Hagland)  _readline->kill(sp, ep);
53fa181999-04-02David Hedbor  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void kill_line() {
ead9722003-01-20Martin Nilsson  _readline->kill(_readline->getcursorpos(), sizeof(_readline->gettext()));
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void kill_whole_line() {
ead9722003-01-20Martin Nilsson  _readline->kill(0, sizeof(_readline->gettext()));
8e317d1999-06-06Mirar (Pontus Hagland)  }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void yank() { _readline->setmark(_readline->getcursorpos()); _readline->insert(_readline->kill_ring_yank(),_readline->getcursorpos()); }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void kill_ring_save() { _readline->add_to_kill_ring(_readline->region()); }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void kill_region() { _readline->kill(@_readline->pointmark()); }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void set_mark() { _readline->setmark(_readline->getcursorpos()); }
56e4b02003-06-27Martin Nilsson  //!
8e317d1999-06-06Mirar (Pontus Hagland)  void swap_mark_and_point() { int p=_readline->getcursorpos(); _readline->setcursorpos(_readline->getmark()); _readline->setmark(p);
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void redisplay() { _readline->redisplay(0); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void clear_screen() { _readline->redisplay(1); }
9eaf1d2008-06-28Martin Nilsson  protected array(array(string|function)) default_bindings = ({
f9322c1999-03-13Marcus Comstedt  ({ "^[[A", up_history }), ({ "^[[B", down_history }), ({ "^[[C", forward_char }), ({ "^[[D", backward_char }),
aef0f12004-11-02Martin Stjernholm  ({ "^[^[[C", forward_word }), ({ "^[^[[D", backward_word }),
f566a01999-04-25Marcus Comstedt  ({ "^[C", capitalize_word }), ({ "^[c", capitalize_word }), ({ "^[U", upcase_word }), ({ "^[u", upcase_word }), ({ "^[L", downcase_word }), ({ "^[l", downcase_word }),
8e317d1999-06-06Mirar (Pontus Hagland)  ({ "^[D", kill_word }), ({ "^[^H", backward_kill_word }), ({ "^[^?", backward_kill_word }), ({ "^[d", kill_word }),
f566a01999-04-25Marcus Comstedt  ({ "^[F", forward_word }), ({ "^[B", backward_word }), ({ "^[f", forward_word }), ({ "^[b", backward_word }),
8e317d1999-06-06Mirar (Pontus Hagland)  ({ "^[w", kill_ring_save }), ({ "^[W", kill_ring_save }), ({ "^0", set_mark }),
f9322c1999-03-13Marcus Comstedt  ({ "^A", beginning_of_line }), ({ "^B", backward_char }), ({ "^D", delete_char_or_eof }), ({ "^E", end_of_line }), ({ "^F", forward_char }), ({ "^H", backward_delete_char }), ({ "^J", newline }), ({ "^K", kill_line }), ({ "^L", clear_screen }), ({ "^M", newline }), ({ "^N", down_history }), ({ "^P", up_history }), ({ "^R", redisplay }), ({ "^T", transpose_chars }), ({ "^U", kill_whole_line }), ({ "^V", quoted_insert }),
8e317d1999-06-06Mirar (Pontus Hagland)  ({ "^W", kill_region }), ({ "^Y", yank }),
f9322c1999-03-13Marcus Comstedt  ({ "^?", backward_delete_char }),
75b76a2004-11-02Henrik Grubbström (Grubba)  ({ "^X^X", swap_mark_and_point }), // Termcap-style
f9322c1999-03-13Marcus Comstedt  ({ "\\!ku", up_history }), ({ "\\!kd", down_history }), ({ "\\!kr", forward_char }),
53fa181999-04-02David Hedbor  ({ "\\!kl", backward_char }),
aef0f12004-11-02Martin Stjernholm  ({ "^[\\!kr", forward_word }), ({ "^[\\!kl", backward_word }),
75b76a2004-11-02Henrik Grubbström (Grubba)  ({ "\\!kD", delete_char }), ({ "\\!kb", backward_delete_char }), ({ "^[\\!kD", kill_word }), ({ "^[\\!kb", backward_kill_word }), ({ "\\!kh", beginning_of_line }),
b809002004-11-02Martin Stjernholm  ({ "\\!@7", end_of_line }), ({ "\\!@8", newline }), ({ "\\!ho", beginning_of_line }),
75b76a2004-11-02Henrik Grubbström (Grubba)  // Terminfo-style ({ "\\!kcuu1", up_history }), ({ "\\!kcud1", down_history }), ({ "\\!kcuf1", forward_char }), ({ "\\!kcub1", backward_char }),
aef0f12004-11-02Martin Stjernholm  ({ "^[\\!kcuf1", forward_word }), ({ "^[\\!kcub1", backward_word }),
75b76a2004-11-02Henrik Grubbström (Grubba)  ({ "\\!kdch1", delete_char }), ({ "\\!kbs", backward_delete_char }), ({ "^[\\!kdch1", kill_word }), ({ "^[\\!kbs", backward_kill_word }), ({ "\\!khome", beginning_of_line }), ({ "\\!kend", end_of_line }), ({ "\\!kent", newline }),
b809002004-11-02Martin Stjernholm  ({ "\\!home", beginning_of_line }),
f9322c1999-03-13Marcus Comstedt  });
56e4b02003-06-27Martin Nilsson  //!
9eaf1d2008-06-28Martin Nilsson  protected void set_default_bindings()
f9322c1999-03-13Marcus Comstedt  { 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);
b090761999-06-11Marcus Comstedt  if(ic->dumb) { ic->bind("^J", newline); return; }
6dd2821999-04-02David Hedbor 
f9322c1999-03-13Marcus Comstedt  foreach(default_bindings, array(string|function) b) ic->bind(@b); }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void create(object readline) { _readline = readline; set_default_bindings(); } }
492a0d2003-07-19Martin Nilsson //!
f9322c1999-03-13Marcus Comstedt class History {
9eaf1d2008-06-28Martin Nilsson  protected private array(string) historylist; protected private mapping(int:string) historykeep=([]); protected private int minhistory, maxhistory, historynum;
f9322c1999-03-13Marcus Comstedt 
56e4b02003-06-27Martin Nilsson  //!
ad50fc1999-10-26Johan Schön  string encode()
ce5a241999-10-04Johan Schön  {
ad50fc1999-10-26Johan Schön  return historylist*"\n";
ce5a241999-10-04Johan Schön  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  int get_history_num() { return historynum; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  string history(int n, string text) { if (n<minhistory) n = minhistory; else if (n-minhistory>=sizeof(historylist)) n = sizeof(historylist)+minhistory-1;
657ade1999-03-14Marcus Comstedt  if(text != historylist[historynum-minhistory]) { if(!historykeep[historynum]) historykeep[historynum] = historylist[historynum-minhistory]; historylist[historynum-minhistory]=text; }
f9322c1999-03-13Marcus Comstedt  return historylist[(historynum=n)-minhistory]; }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  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;
657ade1999-03-14Marcus Comstedt  historykeep = ([]);
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void finishline(string text) {
657ade1999-03-14Marcus Comstedt  foreach(indices(historykeep), int n) historylist[n-minhistory]=historykeep[n];
ec8a231999-04-29Fredrik Hübinette (Hubbe)  historykeep = ([]);
657ade1999-03-14Marcus Comstedt  historylist[-1] = text; if(sizeof(historylist)>1 && historylist[-2]==historylist[-1])
8a531a2006-11-04Martin Nilsson  historylist = historylist[..<1];
f9322c1999-03-13Marcus Comstedt  }
56e4b02003-06-27Martin Nilsson  //!
f9322c1999-03-13Marcus Comstedt  void set_max_history(int maxhist) { maxhistory = maxhist; }
56e4b02003-06-27Martin Nilsson  //!
ce5a241999-10-04Johan Schön  void create(int maxhist, void|array(string) hist)
f9322c1999-03-13Marcus Comstedt  {
ce5a241999-10-04Johan Schön  historylist = hist || ({ "" });
f9322c1999-03-13Marcus Comstedt  minhistory = historynum = 0; maxhistory = maxhist; } }
9eaf1d2008-06-28Martin Nilsson protected private OutputController output_controller; protected private InputController input_controller; protected private string prompt=""; protected private array(string) prompt_attrs=0; protected private string text="", readtext; protected private function(string:void) newline_func; protected private int cursorpos = 0; protected private int mark = 0;
ff70fc2003-05-04Martin Nilsson /*static private */ History historyobj = 0;
9eaf1d2008-06-28Martin Nilsson protected private int hide = 0;
f9322c1999-03-13Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson protected private array(string) kill_ring=({}); protected private int kill_ring_size=30;
8e317d1999-06-06Mirar (Pontus Hagland) 
ef3ac42002-10-29H. William Welliver III //! get current output control object //! @returns //! Terminal output controller object
ff70fc2003-05-04Martin Nilsson OutputController get_output_controller()
1933461999-03-15Marcus Comstedt { return output_controller; }
f9322c1999-03-13Marcus Comstedt 
ef3ac42002-10-29H. William Welliver III //! get current input control object //! @returns //! Terminal input controller object
ff70fc2003-05-04Martin Nilsson InputController get_input_controller()
1933461999-03-15Marcus Comstedt { return input_controller; }
f9322c1999-03-13Marcus Comstedt 
ef3ac42002-10-29H. William Welliver III //! Return the current prompt string.
1933461999-03-15Marcus Comstedt string get_prompt() { return prompt; }
f9322c1999-03-13Marcus Comstedt 
ef3ac42002-10-29H. William Welliver III //! Set the prompt string. //! @param newp //! New prompt string //! @param newattrs //! Terminal attributes
89e0502000-08-29Fredrik Noring string set_prompt(string newp, array(string)|void newattrs)
1933461999-03-15Marcus Comstedt {
dfb4ab2000-10-10Fredrik Hübinette (Hubbe) // werror("READLINE: Set prompt: %O\n",newp);
1933461999-03-15Marcus Comstedt  string oldp = prompt;
89e0502000-08-29Fredrik Noring  if(newp!=prompt || !equal(prompt_attrs, newattrs))
ec8a231999-04-29Fredrik Hübinette (Hubbe)  {
dfb4ab2000-10-10Fredrik Hübinette (Hubbe)  prompt = newp; prompt_attrs = newattrs && copy_value(newattrs); if(newline_func) redisplay(0);
ec8a231999-04-29Fredrik Hübinette (Hubbe)  }
1933461999-03-15Marcus Comstedt  return oldp; }
f9322c1999-03-13Marcus Comstedt 
ef3ac42002-10-29H. William Welliver III //! Set text echo on or off. //! @param onoff //! 1 for echo, 0 for no echo.
ec8a231999-04-29Fredrik Hübinette (Hubbe) void set_echo(int onoff) { hide=!onoff; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt string gettext() { return text; }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt int getcursorpos() { return cursorpos; }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt int setcursorpos(int p) { if (p<0) p = 0;
ead9722003-01-20Martin Nilsson  if (p>sizeof(text)) p = sizeof(text);
1933461999-03-15Marcus Comstedt  if (p<cursorpos)
f9322c1999-03-13Marcus Comstedt  {
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) output_controller->move_backward(text[p..cursorpos-1]);
1933461999-03-15Marcus Comstedt  cursorpos = p;
f9322c1999-03-13Marcus Comstedt  }
1933461999-03-15Marcus Comstedt  else if (p>cursorpos)
f9322c1999-03-13Marcus Comstedt  {
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) output_controller->move_forward(text[cursorpos..p-1]);
1933461999-03-15Marcus Comstedt  cursorpos = p;
f9322c1999-03-13Marcus Comstedt  }
1933461999-03-15Marcus Comstedt  return cursorpos; }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) int setmark(int p) { if (p<0) p = 0;
ead9722003-01-20Martin Nilsson  if (p>sizeof(text)) p = sizeof(text);
8e317d1999-06-06Mirar (Pontus Hagland)  mark=p; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) int getmark() { return mark; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void insert(string s, int p) { if (p<0) p = 0;
ead9722003-01-20Martin Nilsson  if (p>sizeof(text)) p = sizeof(text);
1933461999-03-15Marcus Comstedt  setcursorpos(p);
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) output_controller->write(s,0,hide);
ead9722003-01-20Martin Nilsson  cursorpos += sizeof(s);
1933461999-03-15Marcus Comstedt  string rest = text[p..];
ead9722003-01-20Martin Nilsson  if (sizeof(rest) && !input_controller->dumb)
1933461999-03-15Marcus Comstedt  {
0c06b31999-06-09Marcus Comstedt  output_controller->write(rest,0,hide);
1933461999-03-15Marcus Comstedt  output_controller->move_backward(rest); } text = text[..p-1]+s+rest;
8e317d1999-06-06Mirar (Pontus Hagland) 
ead9722003-01-20Martin Nilsson  if (mark>p) mark+=sizeof(s);
1933461999-03-15Marcus Comstedt }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void delete(int p1, int p2) { if (p1<0) p1 = 0;
ead9722003-01-20Martin Nilsson  if (p2>sizeof(text)) p2 = sizeof(text);
1933461999-03-15Marcus Comstedt  setcursorpos(p1); if (p1>=p2) return;
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) { output_controller->write(text[p2..],0,hide); output_controller->erase(text[p1..p2-1]); }
1933461999-03-15Marcus Comstedt  text = text[..p1-1]+text[p2..];
8e317d1999-06-06Mirar (Pontus Hagland)  if (mark>p2) mark-=(p2-p1); else if (mark>p1) mark=p1;
ead9722003-01-20Martin Nilsson  cursorpos = sizeof(text);
1933461999-03-15Marcus Comstedt  setcursorpos(p1); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) array(int) pointmark() // returns point and mark in numeric order { int p1,p2; p1=getcursorpos(),p2=getmark(); if (p1>p2) return ({p2,p1}); return ({p1,p2}); }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) string region(int ... args) /* p1, p2 or point-mark */ { int p1,p2; if (sizeof(args)) [p1,p2]=args; else [p1,p2]=pointmark(); return text[p1..p2-1]; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) void kill(int p1, int p2) { if (p1<0) p1 = 0;
ead9722003-01-20Martin Nilsson  if (p2>sizeof(text)) p2 = sizeof(text);
8e317d1999-06-06Mirar (Pontus Hagland)  if (p1>=p2) return; add_to_kill_ring(text[p1..p2-1]); delete(p1,p2); }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) void add_to_kill_ring(string s) { kill_ring+=({s}); if (sizeof(kill_ring)>kill_ring_size) kill_ring=kill_ring[1..]; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
8e317d1999-06-06Mirar (Pontus Hagland) string kill_ring_yank() { if (!sizeof(kill_ring)) return ""; return kill_ring[-1]; }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void history(int n) { if(historyobj) { string h = historyobj->history(n, text);
ead9722003-01-20Martin Nilsson  delete(0, sizeof(text)+sizeof(prompt));
1933461999-03-15Marcus Comstedt  insert(h, 0);
f9322c1999-03-13Marcus Comstedt  }
1933461999-03-15Marcus Comstedt }
f9322c1999-03-13Marcus Comstedt 
ab9b982002-11-26Johan Sundström //! Changes the line to a line from the history @[d] steps from the //! current entry (0 being the current line, negative values older, //! and positive values newer). //! @note //! Only effective if you have a history object.
1933461999-03-15Marcus Comstedt void delta_history(int d) { if(historyobj) history(historyobj->get_history_num()+d); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void redisplay(int clear, int|void nobackup) { int p = cursorpos; if(clear) output_controller->clear(); else if(!nobackup) { setcursorpos(0); output_controller->bol(); output_controller->clear(1); } output_controller->check_columns();
ec8a231999-04-29Fredrik Hübinette (Hubbe) 
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) {
dfb4ab2000-10-10Fredrik Hübinette (Hubbe)  if(newline_func) {
89e0502000-08-29Fredrik Noring  if(prompt_attrs) output_controller->turn_on(@prompt_attrs);
b090761999-06-11Marcus Comstedt  output_controller->write(prompt);
89e0502000-08-29Fredrik Noring  if(prompt_attrs) output_controller->turn_off(@prompt_attrs); }
b090761999-06-11Marcus Comstedt  output_controller->write(text,0,hide); }
1933461999-03-15Marcus Comstedt  cursorpos = sizeof(text); setcursorpos(p); }
17bc0b1999-03-14Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson protected private void initline()
1933461999-03-15Marcus Comstedt { text = ""; cursorpos = 0; if (historyobj) historyobj->initline(); }
17bc0b1999-03-14Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt string newline() { setcursorpos(sizeof(text));
b090761999-06-11Marcus Comstedt  if(!input_controller->dumb) output_controller->newline(); else output_controller->bol();
1933461999-03-15Marcus Comstedt  string data = text;
ec8a231999-04-29Fredrik Hübinette (Hubbe)  if (historyobj && !hide)
1933461999-03-15Marcus Comstedt  historyobj->finishline(text); initline(); if(newline_func) newline_func(data); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void eof() { if (historyobj) historyobj->finishline(text); initline(); if(newline_func) newline_func(0); }
f9322c1999-03-13Marcus Comstedt 
ef3ac42002-10-29H. William Welliver III //! Print a message to the output device
1933461999-03-15Marcus Comstedt void message(string msg) { int p = cursorpos;
ead9722003-01-20Martin Nilsson  setcursorpos(sizeof(text));
1933461999-03-15Marcus Comstedt  output_controller->newline(); foreach(msg/"\n", string l) { output_controller->write(l); output_controller->newline();
f9322c1999-03-13Marcus Comstedt  }
1933461999-03-15Marcus Comstedt  redisplay(0, 1); setcursorpos(p); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
ec8a231999-04-29Fredrik Hübinette (Hubbe) void write(string msg,void|int word_wrap) { int p = cursorpos; array(string) tmp=msg/"\n";
8a531a2006-11-04Martin Nilsson  foreach(tmp[..<1],string l)
ec8a231999-04-29Fredrik Hübinette (Hubbe)  {
0c06b31999-06-09Marcus Comstedt  output_controller->write(l,word_wrap);
ec8a231999-04-29Fredrik Hübinette (Hubbe)  output_controller->newline(); }
0c06b31999-06-09Marcus Comstedt  output_controller->write(tmp[-1],word_wrap);
ec8a231999-04-29Fredrik Hübinette (Hubbe) 
ead9722003-01-20Martin Nilsson  cursorpos=sizeof(text);
ec8a231999-04-29Fredrik Hübinette (Hubbe)  redisplay(0, 1); setcursorpos(p); }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void list_completions(array(string) c) {
ec8a231999-04-29Fredrik Hübinette (Hubbe)  message(sprintf("%-*#s",output_controller->get_number_of_columns(),
1933461999-03-15Marcus Comstedt  c*"\n")); }
f9322c1999-03-13Marcus Comstedt 
9eaf1d2008-06-28Martin Nilsson protected private void read_newline(string s)
1933461999-03-15Marcus Comstedt { input_controller->disable(); readtext = s; }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void set_nonblocking(function f) {
dfb4ab2000-10-10Fredrik Hübinette (Hubbe)  int p=cursorpos;
ff62d71999-03-23Marcus Comstedt  if (newline_func = f) { output_controller->enable();
1933461999-03-15Marcus Comstedt  input_controller->enable();
dfb4ab2000-10-10Fredrik Hübinette (Hubbe)  output_controller->bol(); output_controller->clear(1); cursorpos=p; redisplay(0,1);
ff62d71999-03-23Marcus Comstedt  } else {
dfb4ab2000-10-10Fredrik Hübinette (Hubbe)  setcursorpos(0); output_controller->bol(); output_controller->clear(1); cursorpos=p;
1933461999-03-15Marcus Comstedt  input_controller->disable();
ff62d71999-03-23Marcus Comstedt  output_controller->disable(); }
f9322c1999-03-13Marcus Comstedt }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
1933461999-03-15Marcus Comstedt void set_blocking() { set_nonblocking(0); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
89e0502000-08-29Fredrik Noring string edit(string data, string|void local_prompt, array(string)|void attrs)
1933461999-03-15Marcus Comstedt {
ead9722003-01-20Martin Nilsson  if(data && sizeof(data) && input_controller->dumb)
6616c72000-01-09Fredrik Hübinette (Hubbe)  {
90429a2000-09-04Fredrik Noring  string ret=edit("", (local_prompt || get_prompt()) +"["+data+"] ", attrs);
ead9722003-01-20Martin Nilsson  return (!ret || !sizeof(ret))?data:ret;
6616c72000-01-09Fredrik Hübinette (Hubbe)  }
e6ba311999-09-10Fredrik Noring  string old_prompt;
89e0502000-08-29Fredrik Noring  array(string) old_attrs;
1933461999-03-15Marcus Comstedt  if(newline_func == read_newline) return 0;
e6ba311999-09-10Fredrik Noring  if(local_prompt) { old_prompt = get_prompt();
89e0502000-08-29Fredrik Noring  old_attrs = prompt_attrs; set_prompt(local_prompt, attrs);
e6ba311999-09-10Fredrik Noring  }
1933461999-03-15Marcus Comstedt  function oldnl = newline_func;
89e0502000-08-29Fredrik Noring  if(attrs) output_controller->turn_on(@attrs);
5b4d991999-06-09Marcus Comstedt  output_controller->write(local_prompt||prompt);
89e0502000-08-29Fredrik Noring  if(attrs) output_controller->turn_off(@attrs);
1933461999-03-15Marcus Comstedt  initline(); newline_func = read_newline; readtext = "";
ff62d71999-03-23Marcus Comstedt  output_controller->enable();
5b4d991999-06-09Marcus Comstedt  insert(data, 0);
74faa41999-03-23Marcus Comstedt  int res = input_controller->run_blocking();
ce5a241999-10-04Johan Schön 
1933461999-03-15Marcus Comstedt  set_nonblocking(oldnl);
e6ba311999-09-10Fredrik Noring  if(local_prompt)
89e0502000-08-29Fredrik Noring  set_prompt(old_prompt, old_attrs);
e6ba311999-09-10Fredrik Noring 
74faa41999-03-23Marcus Comstedt  return (res>=0 || sizeof(readtext)) && readtext;
1933461999-03-15Marcus Comstedt }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
89e0502000-08-29Fredrik Noring string read(string|void prompt, array(string)|void attrs)
5b4d991999-06-09Marcus Comstedt {
89e0502000-08-29Fredrik Noring  return edit("", prompt, attrs);
5b4d991999-06-09Marcus Comstedt }
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
ff70fc2003-05-04Martin Nilsson void enable_history(array(string)|History|int hist)
1933461999-03-15Marcus Comstedt { if (objectp(hist)) historyobj = hist;
ce5a241999-10-04Johan Schön  else if(arrayp(hist)) historyobj = History(512,hist);
1933461999-03-15Marcus Comstedt  else if(!hist) historyobj = 0; else if(historyobj) historyobj->set_max_history(hist); else historyobj = History(hist); }
f9322c1999-03-13Marcus Comstedt 
6c00e02001-10-23Martin Nilsson //! @fixme //! Document this function
ce5a241999-10-04Johan Schön History get_history() { return historyobj; }
9eaf1d2008-06-28Martin Nilsson protected void destroy()
56e4b02003-06-27Martin Nilsson { if(input_controller) destruct(input_controller); if(output_controller) destruct(output_controller); }
6c00e02001-10-23Martin Nilsson //! Creates a Readline object, that takes input from @[infd] and has output //! on @[outfd]. //! //! @param infd
56e4b02003-06-27Martin Nilsson //! Defaults to @[Stdio.stdin].
6c00e02001-10-23Martin Nilsson //! //! @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].
1933461999-03-15Marcus Comstedt void create(object|void infd, object|string|void interm, object|void outfd, object|string|void outterm)
f9322c1999-03-13Marcus Comstedt {
56e4b02003-06-27Martin Nilsson  atexit(destroy);
1933461999-03-15Marcus Comstedt  output_controller = OutputController(outfd || infd, outterm || interm); input_controller = InputController(infd, interm);
56e4b02003-06-27Martin Nilsson  DefaultEditKeys(this);
f9322c1999-03-13Marcus Comstedt }