source: editwin.c @ 6073462

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 6073462 was 6073462, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
make owl_editwin_adjust_for_locktext go away (and cleanse owl_editwin_clear slightly)
  • Property mode set to 100644
File size: 25.7 KB
RevLine 
[7d4fbcd]1#include "owl.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
[10b866d]5#include <ctype.h>
[7d4fbcd]6
[1aee7d9]7static const char fileIdent[] = "$Id$";
8
[a556caa]9struct _owl_editwin { /*noproto*/
10  char *buff;
11  owl_history *hist;
12  int bufflen;
13  int allocated;
14  int index;
15  int goal_column;
16  int topindex;
17  int winlines, wincols, fillcol, wrapcol;
18  WINDOW *curswin;
19  int style;
20  int lock;
21  int dotsend;
22  int echochar;
23
24  char *command;
25  void (*callback)(struct _owl_editwin*);
26  void *cbdata;
27};
28
29typedef struct { /*noproto*/
30  int index;
31  int goal_column;
[a0fbdee]32  int lock;
33} oe_excursion;
[a556caa]34
[e20d8179]35static int owl_editwin_is_char_in(owl_editwin *e, char *set);
36static void oe_reframe(owl_editwin *e);
37
[7d4fbcd]38#define INCR 5000
39
[a556caa]40#define WHITESPACE " \n\t"
41
42owl_editwin *owl_editwin_allocate(void) {
43  return owl_malloc(sizeof(owl_editwin));
44}
45
[cf83b7a]46/* initialize the editwin e.
47 * 'win' is an already initialzed curses window that will be used by editwin
48 */
[c9334b1]49void owl_editwin_init(owl_editwin *e, WINDOW *win, int winlines, int wincols, int style, owl_history *hist)
50{
[e20d8179]51  e->buff=owl_malloc(INCR);
[7d4fbcd]52  e->buff[0]='\0';
53  e->bufflen=0;
[10b866d]54  e->hist=hist;
[7d4fbcd]55  e->allocated=INCR;
[a556caa]56  e->index = 0;
57  e->goal_column = -1;
58  e->topindex=0;
[7d4fbcd]59  e->winlines=winlines;
60  e->wincols=wincols;
[9a6cc40]61  e->fillcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxfillcols(&g));
62  e->wrapcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxwrapcols(&g));
[7d4fbcd]63  e->curswin=win;
64  e->style=style;
65  if ((style!=OWL_EDITWIN_STYLE_MULTILINE) &&
66      (style!=OWL_EDITWIN_STYLE_ONELINE)) {
67    e->style=OWL_EDITWIN_STYLE_MULTILINE;
68  }
69  e->lock=0;
70  e->dotsend=0;
[c9334b1]71  e->echochar='\0';
[e74c01c]72
[af1920fd]73  /* We get initialized multiple times, but we need to hold on to
74     the callbacks, so we can't NULL them here. */
[e74c01c]75  /*
76    e->command = NULL;
77    e->callback = NULL;
78    e->cbdata = NULL;
79  */
[7d4fbcd]80  if (win) werase(win);
81}
82
[c9334b1]83void owl_editwin_set_curswin(owl_editwin *e, WINDOW *w, int winlines, int wincols)
84{
[7d4fbcd]85  e->curswin=w;
86  e->winlines=winlines;
87  e->wincols=wincols;
[9a6cc40]88  e->fillcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxfillcols(&g));
89  e->wrapcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxwrapcols(&g));
[7d4fbcd]90}
91
[c9334b1]92/* echo the character 'ch' for each normal character keystroke,
93 * excepting locktext.  This is useful for entering passwords etc.  If
94 * ch=='\0' characters are echo'd normally
95 */
96void owl_editwin_set_echochar(owl_editwin *e, int ch)
97{
98  e->echochar=ch;
99}
100
101WINDOW *owl_editwin_get_curswin(owl_editwin *e)
102{
[060b3b4]103  return(e->curswin);
[7d4fbcd]104}
105
[c9334b1]106void owl_editwin_set_history(owl_editwin *e, owl_history *h)
107{
[060b3b4]108  e->hist=h;
[10b866d]109}
110
[c9334b1]111owl_history *owl_editwin_get_history(owl_editwin *e)
112{
[060b3b4]113  return(e->hist);
[10b866d]114}
115
[c9334b1]116void owl_editwin_set_dotsend(owl_editwin *e)
117{
[7d4fbcd]118  e->dotsend=1;
119}
120
[e74c01c]121void owl_editwin_set_command(owl_editwin *e, char *command) {
122  if(e->command) owl_free(e->command);
123  e->command = owl_strdup(command);
124}
125
126char *owl_editwin_get_command(owl_editwin *e) {
127  if(e->command) return e->command;
128  return "";
129}
130
131void owl_editwin_set_callback(owl_editwin *e, void (*cb)(owl_editwin*)) {
132  e->callback = cb;
133}
134
135void (*owl_editwin_get_callback(owl_editwin *e))(owl_editwin*) {
136  return e->callback;
137}
138
139void owl_editwin_set_cbdata(owl_editwin *e, void *data) {
140  e->cbdata = data;
141}
142
[a556caa]143void *owl_editwin_get_cbdata(owl_editwin *e) {
[e74c01c]144  return e->cbdata;
145}
146
147void owl_editwin_do_callback(owl_editwin *e) {
148  void (*cb)(owl_editwin*);
149  cb=owl_editwin_get_callback(e);
150  if(!cb) {
151    owl_function_error("Internal error: No editwin callback!");
152  } else {
[af1920fd]153    /* owl_function_error("text: |%s|", owl_editwin_get_text(e)); */
[e74c01c]154    cb(e);
155  }
156}
157
[c9334b1]158int owl_editwin_limit_maxcols(int v, int maxv)
159{
[d36f2cb]160  if (maxv > 5 && v > maxv) {
[060b3b4]161    return(maxv);
[d36f2cb]162  } else {
[060b3b4]163    return(v);
[d36f2cb]164  }
165}
166
[c9334b1]167/* set text to be 'locked in' at the beginning of the buffer, any
168 * previous text (including locked text) will be overwritten
169 */
170void owl_editwin_set_locktext(owl_editwin *e, char *text)
171{
[a556caa]172  e->index = 0;
[7d4fbcd]173  owl_editwin_overwrite_string(e, text);
[47519e1b]174  owl_editwin_overwrite_char(e, '\0');
[7d4fbcd]175  e->lock=strlen(text);
[a556caa]176  e->index = e->lock;
[7d4fbcd]177  owl_editwin_redisplay(e, 0);
178}
179
[c9334b1]180int owl_editwin_get_style(owl_editwin *e)
181{
[7d4fbcd]182  return(e->style);
183}
184
[c9334b1]185void owl_editwin_new_style(owl_editwin *e, int newstyle, owl_history *h)
186{
[7d4fbcd]187  char *ptr;
[10b866d]188
189  owl_editwin_set_history(e, h);
[7d4fbcd]190  if (e->style==newstyle) return;
191
192  if (newstyle==OWL_EDITWIN_STYLE_MULTILINE) {
193    e->style=newstyle;
194  } else if (newstyle==OWL_EDITWIN_STYLE_ONELINE) {
195    e->style=newstyle;
196
197    /* nuke everything after the first line */
198    if (e->bufflen > 0) {
199      ptr=strchr(e->buff, '\n')-1;
200      if (ptr) {
201        e->bufflen=ptr - e->buff;
202        e->buff[e->bufflen]='\0';
[a556caa]203        e->index = 0;
[7d4fbcd]204      }
205    }
206  }
207}
208
[c9334b1]209/* completly reinitialize the buffer */
210void owl_editwin_fullclear(owl_editwin *e)
211{
[7d4fbcd]212  owl_free(e->buff);
[10b866d]213  owl_editwin_init(e, e->curswin, e->winlines, e->wincols, e->style, e->hist);
[7d4fbcd]214}
215
[c9334b1]216/* clear all text except for locktext and put the cursor at the
217 * beginning
218 */
219void owl_editwin_clear(owl_editwin *e)
220{
221
[6073462]222  int lock = e->lock;
[10b866d]223  int dotsend=e->dotsend;
[7d4fbcd]224  char *locktext=NULL;
[cc6f009]225  char echochar=e->echochar;
[10b866d]226
[6073462]227  if (lock > 0) {
[7d4fbcd]228    locktext=owl_malloc(e->lock+20);
229    strncpy(locktext, e->buff, e->lock);
230    locktext[e->lock]='\0';
231  }
232
233  owl_free(e->buff);
[10b866d]234  owl_editwin_init(e, e->curswin, e->winlines, e->wincols, e->style, e->hist);
[7d4fbcd]235
236  if (lock > 0) {
237    owl_editwin_set_locktext(e, locktext);
238  }
[10b866d]239  if (dotsend) {
240    owl_editwin_set_dotsend(e);
241  }
[cc6f009]242  if (echochar) {
243    owl_editwin_set_echochar(e, echochar);
244  }
[7d4fbcd]245
246  if (locktext) owl_free(locktext);
[6073462]247
248  e->index = lock;
[7d4fbcd]249}
250
[c9334b1]251/* malloc more space for the buffer */
252void _owl_editwin_addspace(owl_editwin *e)
253{
[7d4fbcd]254  e->buff=owl_realloc(e->buff, e->allocated+INCR);
255  if (!e->buff) {
[a556caa]256    /* error *//*XXXXXXXXXXXXXXXX*/
[7d4fbcd]257    return;
258  }
259  e->allocated+=INCR;
260}
261
[c9334b1]262void owl_editwin_recenter(owl_editwin *e)
263{
[a556caa]264  e->topindex = -1;
265}
[e20d8179]266
[a0fbdee]267static void oe_save_excursion(owl_editwin *e, oe_excursion *x)
268{
269  x->index = e->index;
270  x->goal_column = e->goal_column;
271  x->lock = e->lock;
272}
273
274static void oe_restore_excursion(owl_editwin *e, oe_excursion *x)
275{
276  e->index = x->index;
277  e->goal_column = x->goal_column;
278  e->lock = x->lock;
279}
280
[e20d8179]281static inline char *oe_next_point(owl_editwin *e, char *p)
282{
283  char *boundary = e->buff + e->bufflen + 1;
284  char *q;
285
286  q = g_utf8_find_next_char(p, boundary);
287  while (q && g_unichar_ismark(g_utf8_get_char(q)))
288    q = g_utf8_find_next_char(q, boundary);
289
290  if (q == p)
291    return NULL;
292  return q;
293}
294
295static inline char *oe_prev_point(owl_editwin *e, char *p)
296{
297  char *boundary = e->buff + e->lock;
298
299  p = g_utf8_find_prev_char(boundary, p);
300  while (p && g_unichar_ismark(g_utf8_get_char(p)))
301    p = g_utf8_find_prev_char(boundary, p);
302
303  return p;
304}
305
[19f765d]306static int oe_find_display_line(owl_editwin *e, int *x, int index)
307{
308  int width = 0, cw;
309  gunichar c = -1;
310  char *p;
311
[77d4402]312  while(1) {
313    /* note the position of the dot */
[2021bea]314    if (x != NULL && index == e->index && width < e->wincols)
[19f765d]315      *x = width;
[77d4402]316
[19f765d]317    /* get the current character */
318    c = g_utf8_get_char(e->buff + index);
319
320    /* figure out how wide it is */
321    if (c == 9) /* TAB */
322      cw = TABSIZE - width % TABSIZE;
323    else
324      cw = mk_wcwidth(c);
325    if (cw < 0) /* control characters */
326        cw = 0;
327
[77d4402]328    if (width + cw > e->wincols) {
329      if (x != NULL && *x == width)
330        *x = -1;
[19f765d]331      break;
[77d4402]332    }
[19f765d]333    width += cw;
334
335    if (c == '\n') {
[77d4402]336      if (width < e->wincols)
337        ++index; /* skip the newline */
[19f765d]338      break;
339    }
340
341    /* find the next character */
342    p = oe_next_point(e, e->buff + index);
343    if (p == NULL) { /* we ran off the end */
344      if (x != NULL && e->index > index)
345        *x = width + 1;
346      break;
347    }
348    index = p - e->buff;
[cedc95c]349
[19f765d]350  }
351  return index;
352}
353
[e20d8179]354static void oe_reframe(owl_editwin *e) {
[cedc95c]355  oe_excursion x;
356  int goal = e->winlines / 2;
357  int index;
358  int count = 0;
359  int point;
360  int n, i;
361  int last;
362
363  oe_save_excursion(e, &x);
364  /* step back line-by-line through the buffer until we have >= goal lines of
365     display text */
366  e->lock = 0; /* we can (must) tread on the locktext */
367
368  point = e->index;
369  last = -1;
370  while (count < goal) {
371    index = e->index;
372    owl_editwin_move_to_beginning_of_line(e);
373    if (last == e->index)
374      break;
375    last = e->index;
376    for (n = 0, i = e->index; i < index; n++)
377      i = oe_find_display_line(e, NULL, i);
378    count += n == 0 ? 1 : n;
379    if (count < goal)
380      owl_editwin_point_move(e, -1);
381  }
382  /* if we overshot, backtrack */
383  for (n = 0; n < (count - goal); n++)
384    e->index = oe_find_display_line(e, NULL, e->index);
385
386  e->topindex = e->index;
387
388  oe_restore_excursion(e, &x);
[7d4fbcd]389}
390
[c9334b1]391/* regenerate the text on the curses window */
392/* if update == 1 then do a doupdate(), otherwise do not */
393void owl_editwin_redisplay(owl_editwin *e, int update)
394{
[19f765d]395  int x = -1, y = -1, t;
[77d4402]396  int line, index, lineindex, times = 0;
[7d4fbcd]397
[bd1a1ae]398  do {
[cedc95c]399    werase(e->curswin);
400
[bd1a1ae]401    if (e->topindex == -1 || e->index < e->topindex)
[e20d8179]402      oe_reframe(e);
403
[bd1a1ae]404    line = 0;
405    index = e->topindex;
406    while(line < e->winlines) {
407      lineindex = index;
[19f765d]408      t = -1;
409      index = oe_find_display_line(e, &t, lineindex);
410      if (x == -1 && t != -1)
411        x = t, y = line;
[bd1a1ae]412      if (index - lineindex)
413        mvwaddnstr(e->curswin, line, 0,
414                   e->buff + lineindex,
415                   index - lineindex);
416      line++;
[a556caa]417    }
[19f765d]418    if (x == -1)
[bd1a1ae]419        e->topindex = -1; /* force a reframe */
[77d4402]420    times++;
421  } while(x == -1 && times < 3);
[e20d8179]422
[19f765d]423  wmove(e->curswin, y, x);
[7d4fbcd]424  wnoutrefresh(e->curswin);
[a556caa]425  if (update == 1)
[7d4fbcd]426    doupdate();
427}
428
[47519e1b]429/* Remove n bytes at cursor. */
430void _owl_editwin_remove_bytes(owl_editwin *e, int n) /*noproto*/
431{
[a556caa]432  int i = e->index + n;
[47519e1b]433  for (; i < e->bufflen; i++) {
434    e->buff[i-n] = e->buff[i];
435  }
[e20d8179]436
[47519e1b]437  e->bufflen -= n;
438  e->buff[e->bufflen] = '\0';
439}
[830c36e]440
[47519e1b]441/* Insert n bytes at cursor.*/
442void _owl_editwin_insert_bytes(owl_editwin *e, int n) /*noproto*/
443{
[a556caa]444  int i;
[e9bb404]445
[47519e1b]446  if ((e->bufflen + n) > (e->allocated - 5)) {
447    _owl_editwin_addspace(e);
448  }
449
[a556caa]450  if(e->index != e->bufflen) {
451    for (i = e->bufflen + n - 1; i > e->index; i--) {
[e9bb404]452      e->buff[i] = e->buff[i - n];
453    }
[47519e1b]454  }
[e9bb404]455
456  e->bufflen += n;
457  e->buff[e->bufflen] = '\0';
458
[47519e1b]459}
460
[7d4fbcd]461
[c9334b1]462/* linewrap the word just before the cursor.
463 * returns 0 on success
464 * returns -1 if we could not wrap.
465 */
466int _owl_editwin_linewrap_word(owl_editwin *e)
467{
[84027015]468  int i;
469  char *ptr1, *start;
470  gunichar c;
[7d4fbcd]471
[84027015]472  start = e->buff + e->lock;
473
[a556caa]474  ptr1 = e->buff + e->index;
[84027015]475  ptr1 = g_utf8_find_prev_char(start, ptr1);
476
477  while (ptr1) {
478    c = g_utf8_get_char(ptr1);
479    if (owl_util_can_break_after(c)) {
480      if (c != ' ') {
481        i = ptr1 - e->buff;
[a556caa]482        e->index = i;
[b2c1bd4]483        _owl_editwin_insert_bytes(e, 1);
484        /* _owl_editwin_insert_bytes may move e->buff. */
[84027015]485        ptr1 = e->buff + i;
486      }
487      *ptr1 = '\n';
488      return 0;
[7d4fbcd]489    }
[2d4ff14]490    else if (c == '\n') {
491      return 0;
492    }
[84027015]493    ptr1 = g_utf8_find_prev_char(start, ptr1);
[7d4fbcd]494  }
[84027015]495  return -1;
[7d4fbcd]496}
497
[c9334b1]498/* insert a character at the current point (shift later
499 * characters over)
500 */
[47519e1b]501void owl_editwin_insert_char(owl_editwin *e, gunichar c)
[c9334b1]502{
[a556caa]503  int i, ret, len;
[47519e1b]504  char tmp[6];
505  memset(tmp, '\0', 6);
[830c36e]506
[7d4fbcd]507  /* \r is \n */
[47519e1b]508  if (c == '\r') {
509    c = '\n';
[7d4fbcd]510  }
511
[47519e1b]512  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
[7d4fbcd]513    /* perhaps later this will change some state that allows the string
514       to be read */
515    return;
516  }
517
[47519e1b]518  g_unichar_to_utf8(c, tmp);
519  len = strlen(tmp);
[830c36e]520
[7d4fbcd]521  /* make sure there is enough memory for the new text */
[47519e1b]522  if ((e->bufflen + len) > (e->allocated - 5)) {
[7d4fbcd]523    _owl_editwin_addspace(e);
524  }
525
526  /* If we're going to insert at the last column do word wrapping, unless it's a \n */
[a556caa]527#if 0 /* XXX */
[47519e1b]528  if ((e->buffx + 1 == e->wrapcol) && (c != '\n')) {
529    ret = _owl_editwin_linewrap_word(e);
530    if (ret == -1) {
[7d4fbcd]531      /* we couldn't wrap, insert a hard newline instead */
532      owl_editwin_insert_char(e, '\n');
533    }
534  }
[a556caa]535#endif
[7d4fbcd]536
537  /* shift all the other characters right */
[e9bb404]538  _owl_editwin_insert_bytes(e, len);
[7d4fbcd]539
[47519e1b]540  /* insert the new character */
541  for(i = 0; i < len; i++) {
[a556caa]542    e->buff[e->index + i] = tmp[i];
[47519e1b]543  }
[7d4fbcd]544
545  /* advance the cursor */
[a556caa]546  e->index += len;
[7d4fbcd]547}
548
[c9334b1]549/* overwrite the character at the current point with 'c' */
[47519e1b]550void owl_editwin_overwrite_char(owl_editwin *e, gunichar c)
[c9334b1]551{
[a556caa]552  int oldlen, newlen, i;
553  char tmp[6], *t;
[47519e1b]554  memset(tmp, '\0', 6);
[830c36e]555
[7d4fbcd]556  /* \r is \n */
[47519e1b]557  if (c == '\r') {
558    c = '\n';
[7d4fbcd]559  }
[e20d8179]560
[47519e1b]561  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
[7d4fbcd]562    /* perhaps later this will change some state that allows the string
563       to be read */
564    return;
565  }
566
[47519e1b]567  g_unichar_to_utf8(c, tmp);
568  newlen = strlen(tmp);
[7d4fbcd]569
[a556caa]570  t = g_utf8_find_next_char(e->buff + e->index, NULL);
571  oldlen = (t ? (t - (e->buff + e->index)) : 0);
[7d4fbcd]572
[830c36e]573  /* only if we are at the end of the buffer do we create new space here */
[a556caa]574  if (e->index == e->bufflen) {
[830c36e]575    if ((e->bufflen+newlen) > (e->allocated-5)) {
576      _owl_editwin_addspace(e);
577    }
[7d4fbcd]578  }
[e20d8179]579  /* if not at the end of the buffer, adjust based in char size difference. */
[830c36e]580  else if (oldlen > newlen) {
[47519e1b]581    _owl_editwin_remove_bytes(e, oldlen-newlen);
582  }
583  else /* oldlen < newlen */ {
584    _owl_editwin_insert_bytes(e, newlen-oldlen);
[7d4fbcd]585  }
[47519e1b]586  /* Overwrite the old char*/
587  for (i = 0; i < newlen; i++) {
[a556caa]588    e->buff[e->index + i] = tmp[i];
[47519e1b]589  }
[e20d8179]590
[47519e1b]591  /* housekeeping */
[a556caa]592  if (e->index == e->bufflen) {
[830c36e]593    e->bufflen += newlen;
594    e->buff[e->bufflen] = '\0';
595  }
[e20d8179]596
[47519e1b]597  /* advance the cursor */
[a556caa]598  e->index += newlen;
[7d4fbcd]599}
600
[c9334b1]601/* delete the character at the current point, following chars
602 * shift left.
[e20d8179]603 */
[c9334b1]604void owl_editwin_delete_char(owl_editwin *e)
605{
[47519e1b]606  char *p1, *p2;
607  gunichar c;
[7d4fbcd]608
[47519e1b]609  if (e->bufflen == 0) return;
[e20d8179]610
[a556caa]611  if (e->index == e->bufflen) return;
[7d4fbcd]612
[a556caa]613  p1 = e->buff + e->index;
[47519e1b]614  p2 = g_utf8_next_char(p1);
615  c = g_utf8_get_char(p2);
616  while (g_unichar_ismark(c)) {
617    p2 = g_utf8_next_char(p2);
618    c = g_utf8_get_char(p2);
[7d4fbcd]619  }
[47519e1b]620  _owl_editwin_remove_bytes(e, p2-p1);
[7d4fbcd]621}
622
[c9334b1]623/* Swap the character at point with the character at point-1 and
624 * advance the pointer.  If point is at beginning of buffer do
625 * nothing.  If point is after the last character swap point-1 with
[e20d8179]626 * point-2.  (Behaves as observed in tcsh and emacs).
[c9334b1]627 */
628void owl_editwin_transpose_chars(owl_editwin *e)
629{
[47519e1b]630  char *p1, *p2, *p3, *tmp;
[f2e36b5]631
[47519e1b]632  if (e->bufflen == 0) return;
[e20d8179]633
[a556caa]634  if (e->index == e->bufflen) {
[f2e36b5]635    /* point is after last character */
[a556caa]636    e->index--;
[e20d8179]637  }
[f2e36b5]638
[a556caa]639  if (e->index - 1 < e->lock) {
[f2e36b5]640    /* point is at beginning of buffer, do nothing */
641    return;
642  }
643
[47519e1b]644  /* Transpose two utf-8 unicode glyphs. */
[a556caa]645  p1 = e->buff + e->index;
[47519e1b]646
[e20d8179]647  p2 = oe_next_point(e, p1); /* XXX make sure we can't transpose past the end
648                                of the buffer */
649  if (p2 == NULL)
650    return;
[47519e1b]651
[e20d8179]652  p3 = oe_prev_point(e, p1);
653  if (p3 == NULL)
654    return;
[47519e1b]655
656  tmp = owl_malloc(p2 - p3 + 5);
657  *tmp = '\0';
658  strncat(tmp, p1, p2 - p1);
659  strncat(tmp, p3, p1 - p3);
660  strncpy(p3, tmp, p2 - p3);
661  owl_free(tmp);
[a556caa]662  e->index = p3 - e->buff;
[f2e36b5]663}
664
[c9334b1]665/* insert 'string' at the current point, later text is shifted
666 * right
667 */
668void owl_editwin_insert_string(owl_editwin *e, char *string)
669{
[47519e1b]670  char *p;
671  gunichar c;
672  if (!g_utf8_validate(string, -1, NULL)) {
673    owl_function_debugmsg("owl_editwin_insert_string: received non-utf-8 string.");
674    return;
675  }
676  p = string;
677  c = g_utf8_get_char(p);
678  while (c) {
[fac5463]679    _owl_editwin_process_char(e, c);
[47519e1b]680    p = g_utf8_next_char(p);
681    c = g_utf8_get_char(p);
[7d4fbcd]682  }
683}
684
[c9334b1]685/* write 'string' at the current point, overwriting text that is
686 * already there
687 */
688
689void owl_editwin_overwrite_string(owl_editwin *e, char *string)
690{
[47519e1b]691  char *p;
692  gunichar c;
[7d4fbcd]693
[47519e1b]694  if (!g_utf8_validate(string, -1, NULL)) {
695    owl_function_debugmsg("owl_editwin_overwrite_string: received non-utf-8 string.");
696    return;
697  }
698  p = string;
699  c = g_utf8_get_char(p);
700  while (c) {
701    owl_editwin_overwrite_char(e, c);
702    p = g_utf8_next_char(p);
703    c = g_utf8_get_char(p);
[7d4fbcd]704  }
705}
706
[a556caa]707/* We assume index is not set to point to a mid-char */
708gunichar _owl_editwin_get_char_at_point(owl_editwin *e)
[c9334b1]709{
[a556caa]710  return g_utf8_get_char(e->buff + e->index);
711}
[7d4fbcd]712
[e20d8179]713int owl_editwin_point_move(owl_editwin *e, int delta)
[84027015]714{
[e20d8179]715  char *p;
[19f765d]716  int change, d = 0;
[a556caa]717
718  change = MAX(delta, - delta);
719  p = e->buff + e->index;
720
721  while (d < change && p != NULL) {
[e20d8179]722    if (delta > 0)
723      p = oe_next_point(e, p);
724    else
725      p = oe_prev_point(e, p);
726    if (p != NULL) {
727      e->index = p - e->buff;
728      d++;
[a556caa]729    }
730  }
731
732  if (delta)
733    e->goal_column = -1;
734
735  return delta > 0 ? d : -d;
[84027015]736}
737
[a556caa]738int owl_editwin_at_beginning_of_buffer(owl_editwin *e) {
739  if (e->index == e->lock)
740    return 1;
[84027015]741
[a556caa]742  return 0;
743}
744
745int owl_at_end_of_buffer(owl_editwin *e) {
746  if (e->index == e->bufflen)
747    return 1;
748
749  return 0;
750}
751
752int owl_editwin_at_beginning_of_line(owl_editwin *e) /*noproto*/
[c9334b1]753{
[a0fbdee]754  oe_excursion x;
[a556caa]755  int ret;
[47519e1b]756
[a556caa]757  if (owl_editwin_at_beginning_of_buffer(e))
758    return 1;
[47519e1b]759
[a0fbdee]760  oe_save_excursion(e, &x);
[a556caa]761  owl_editwin_point_move(e, -1);
762  ret = (_owl_editwin_get_char_at_point(e) == '\n');
[a0fbdee]763  oe_restore_excursion(e, &x);
[a556caa]764
765  return ret;
766}
767
[e20d8179]768static int owl_editwin_is_char_in(owl_editwin *e, char *set)
[a556caa]769{
770  char *p;
771  /* It would be awfully nice if we could do UTF-8 comparisons */
772  for (p = set; *p != 0; p++)
773    if (_owl_editwin_get_char_at_point(e) == *p)
774      return 1;
775  return 0;
776}
777
[e20d8179]778int owl_editwin_move_if_in(owl_editwin *e, int delta, char *set)
[a556caa]779{
780  int change, distance = 0;
[e20d8179]781  while (owl_editwin_is_char_in(e, set)) {
[a556caa]782    change = owl_editwin_point_move(e, delta);
783    distance += change;
784    if (change == 0)
785      break;
[47519e1b]786  }
[a556caa]787  return distance;
788}
789
[e20d8179]790int owl_editwin_move_if_not_in(owl_editwin *e, int delta, char *set)
[a556caa]791{
792  int change, distance = 0;
[e20d8179]793  while (!owl_editwin_is_char_in(e, set)) {
[a556caa]794    change = owl_editwin_point_move(e, delta);
795    distance += change;
796    if (change == 0)
797      break;
[7d4fbcd]798  }
[a556caa]799  return distance;
[7d4fbcd]800}
801
[e20d8179]802int owl_editwin_move_to_beginning_of_line(owl_editwin *e)
[47519e1b]803{
[a556caa]804  int distance = 0;
[47519e1b]805
[a556caa]806  if (!owl_editwin_at_beginning_of_line(e)) {
807    /* move off the \n if were at the end of a line */
808    distance += owl_editwin_point_move(e, -1);
809    distance += owl_editwin_move_if_not_in(e, -1, "\n");
810    if (distance && !owl_editwin_at_beginning_of_buffer(e))
811      distance += owl_editwin_point_move(e, 1);
[47519e1b]812  }
[77d4402]813  e->goal_column = 0; /* subtleties */
[84027015]814
[a556caa]815  return distance;
816}
[e20d8179]817
818int owl_editwin_move_to_end_of_line(owl_editwin *e)
[a556caa]819{
820  return owl_editwin_move_if_not_in(e, 1, "\n");
[47519e1b]821}
822
[e20d8179]823int owl_editwin_line_move(owl_editwin *e, int delta)
[c9334b1]824{
[d7043b4]825  int goal_column, change, ll, distance;
826  int count = 0;
[a556caa]827
828  change = MAX(delta, -delta);
829
[d7043b4]830  goal_column = e->goal_column;
831  distance = owl_editwin_move_to_beginning_of_line(e);
832  goal_column = goal_column == -1 ? -distance : goal_column;
[a556caa]833
834  while(count < change) {
835    if (delta > 0) {
836      distance += owl_editwin_move_if_not_in(e, 1, "\n");
837      distance += owl_editwin_point_move(e, 1);
838    } else {
839      /* I really want to assert delta < 0 here */
840      distance += owl_editwin_point_move(e, -1); /* to the newline on
841                                                    the previous line */
842      distance += owl_editwin_move_to_beginning_of_line(e);
843    }
844    count++;
[7d4fbcd]845  }
[a556caa]846
847  distance += (ll = owl_editwin_move_to_end_of_line(e));
848  if (ll > goal_column)
849    distance += owl_editwin_point_move(e, goal_column - ll);
850
851  e->goal_column = goal_column;
852
853  return distance;
[7d4fbcd]854}
855
[c9334b1]856void owl_editwin_backspace(owl_editwin *e)
857{
[7d4fbcd]858  /* delete the char before the current one
859   * and shift later chars left
860   */
[a556caa]861  if(owl_editwin_point_move(e, -1))
[7d4fbcd]862    owl_editwin_delete_char(e);
863}
864
[c9334b1]865void owl_editwin_key_up(owl_editwin *e)
866{
[a556caa]867  owl_editwin_line_move(e, -1);
[7d4fbcd]868}
869
[c9334b1]870void owl_editwin_key_down(owl_editwin *e)
871{
[a556caa]872  owl_editwin_line_move(e, 1);
[7d4fbcd]873}
874
[c9334b1]875void owl_editwin_key_left(owl_editwin *e)
876{
[a556caa]877  owl_editwin_point_move(e, -1);
[7d4fbcd]878}
879
[c9334b1]880void owl_editwin_key_right(owl_editwin *e)
881{
[a556caa]882  owl_editwin_point_move(e, 1);
[7d4fbcd]883}
884
[c9334b1]885void owl_editwin_move_to_nextword(owl_editwin *e)
886{
[7d4fbcd]887  /* if we're starting on a space, find the first non-space */
[a556caa]888  owl_editwin_move_if_in(e, 1, WHITESPACE);
[7d4fbcd]889
[a556caa]890  /* now find the end of this word */
891  owl_editwin_move_if_not_in(e, 1, WHITESPACE);
[7d4fbcd]892}
893
[c9334b1]894/* go backwards to the last non-space character
895 */
896void owl_editwin_move_to_previousword(owl_editwin *e)
897{
[a0fbdee]898  oe_excursion x;
[a556caa]899  int beginning;
900  /* if in middle of word, beginning of word */
901
902  /* if at beginning of a word, find beginning of previous word */
903
[e20d8179]904  if (owl_editwin_is_char_in(e, WHITESPACE)) {
[a556caa]905    /* if in whitespace past end of word, find a word , the find the beginning*/
906    owl_editwin_move_if_in(e, -1, WHITESPACE); /* leaves us on the last
907                                                    character of the word */
[a0fbdee]908    oe_save_excursion(e, &x);
[a556caa]909    /* are we at the beginning of a word? */
910    owl_editwin_point_move(e, -1);
[e20d8179]911    beginning = owl_editwin_is_char_in(e, WHITESPACE);
[a0fbdee]912    oe_restore_excursion(e, &x);
[a556caa]913    if (beginning)
914      return;
915   } else {
916    /* in the middle of the word; */
[a0fbdee]917    oe_save_excursion(e, &x);
[a556caa]918    owl_editwin_point_move(e, -1);
[e20d8179]919    if (owl_editwin_is_char_in(e, WHITESPACE)) { /* we were at the beginning */
[a556caa]920      owl_editwin_move_to_previousword(e); /* previous case */
921      return;
922    } else {
[a0fbdee]923      oe_restore_excursion(e, &x);
[7d4fbcd]924    }
925  }
[a556caa]926  owl_editwin_move_if_not_in(e, -1, WHITESPACE);
927  /* will go past */
928  if (e->index > e->lock)
929    owl_editwin_point_move(e, 1);
[7d4fbcd]930}
931
[c9334b1]932void owl_editwin_delete_nextword(owl_editwin *e)
933{
[a0fbdee]934  oe_excursion x;
[a556caa]935  int end;
936
[a0fbdee]937  oe_save_excursion(e, &x);
[a556caa]938  owl_editwin_move_to_nextword(e);
939  end = e->index;
[a0fbdee]940  oe_restore_excursion(e, &x);
[a556caa]941  _owl_editwin_remove_bytes(e, end - e->index);
[7d4fbcd]942}
943
[c9334b1]944void owl_editwin_delete_previousword(owl_editwin *e)
945{
[b68f9cd]946  /* go backwards to the last non-space character, then delete chars */
[84027015]947  int startpos, endpos;
[b68f9cd]948
[a556caa]949  startpos = e->index;
[b68f9cd]950  owl_editwin_move_to_previousword(e);
[a556caa]951  endpos = e->index;
[84027015]952  _owl_editwin_remove_bytes(e, startpos-endpos);
[b68f9cd]953}
954
[a556caa]955void owl_editwin_move_to_line_end(owl_editwin *e)
[c9334b1]956{
[a556caa]957  owl_editwin_move_to_end_of_line(e);
[7d4fbcd]958}
959
[a556caa]960void owl_editwin_delete_to_endofline(owl_editwin *e)
[c9334b1]961{
[a0fbdee]962  oe_excursion x;
[a556caa]963  int end;
964
[a0fbdee]965  oe_save_excursion(e, &x);
[a556caa]966  owl_editwin_move_to_line_end(e);
967  end = e->index;
[a0fbdee]968  oe_restore_excursion(e, &x);
[77d4402]969  if (end - e->index)
970    _owl_editwin_remove_bytes(e, end - e->index);
971  else if (end < e->bufflen)
972    _owl_editwin_remove_bytes(e, 1);
[7d4fbcd]973}
974
[c9334b1]975void owl_editwin_move_to_line_start(owl_editwin *e)
976{
[a556caa]977  owl_editwin_move_to_beginning_of_line(e);
[7d4fbcd]978}
979
[c9334b1]980void owl_editwin_move_to_end(owl_editwin *e)
981{
[a556caa]982  e->index = e->bufflen;
[7d4fbcd]983}
984
[c9334b1]985void owl_editwin_move_to_top(owl_editwin *e)
986{
[a556caa]987  e->index = e->lock;
[7d4fbcd]988}
989
[c9334b1]990void owl_editwin_fill_paragraph(owl_editwin *e)
991{
[a556caa]992#if 0 /* XXX */
[a0fbdee]993  oe_excursion x;
[7d4fbcd]994  int i, save;
995
996  /* save our starting point */
[a0fbdee]997  oe_save_excursion(e, &x);
[a556caa]998
999  save = e->index;
[7d4fbcd]1000
1001  /* scan back to the beginning of this paragraph */
1002  for (i=save; i>=e->lock; i--) {
1003    if ( (i<=e->lock) ||
1004         ((e->buff[i]=='\n') && (e->buff[i-1]=='\n'))) {
[a556caa]1005      e->index = i + 1;
[7d4fbcd]1006      break;
1007    }
1008  }
1009
1010  /* main loop */
1011  while (1) {
[47519e1b]1012    i = _owl_editwin_get_index_from_xy(e);
[7d4fbcd]1013
1014    /* bail if we hit the end of the buffer */
[47519e1b]1015    if (i >= e->bufflen || e->buff[i] == '\0') break;
[7d4fbcd]1016
1017    /* bail if we hit the end of the paragraph */
[47519e1b]1018    if (e->buff[i] == '\n' && e->buff[i+1] == '\n') break;
[7d4fbcd]1019
[50e671c]1020    /* bail if we hit a trailing dot on the buffer */
1021    if (e->buff[i] == '\n' && e->buff[i+1] == '.'
1022        && ((i+2) >= e->bufflen || e->buff[i+2] == '\0'))
1023      break;
1024
[7d4fbcd]1025    /* if we've travelled too far, linewrap */
1026    if ((e->buffx) >= e->fillcol) {
[b2c1bd4]1027      int len = e->bufflen;
[7d4fbcd]1028      _owl_editwin_linewrap_word(e);
[b2c1bd4]1029      /* we may have added a character. */
1030      if (i < save) save += e->bufflen - len;
[a556caa]1031      e->index = i;
[7d4fbcd]1032    }
1033
1034    /* did we hit the end of a line too soon? */
[84027015]1035    /* asedeno: Here we replace a newline with a space. We may want to
1036       consider removing the space if the characters to either side
1037       are CJK ideograms.*/
[47519e1b]1038    i = _owl_editwin_get_index_from_xy(e);
1039    if (e->buff[i] == '\n' && e->buffx < e->fillcol - 1) {
[7d4fbcd]1040      /* ********* we need to make sure we don't pull in a word that's too long ***********/
1041      e->buff[i]=' ';
1042    }
[b2c1bd4]1043
[7d4fbcd]1044    /* fix spacing */
[47519e1b]1045    i = _owl_editwin_get_index_from_xy(e);
1046    if (e->buff[i] == ' ' && e->buff[i+1] == ' ') {
1047      if (e->buff[i-1] == '.' || e->buff[i-1] == '!' || e->buff[i-1] == '?') {
[7d4fbcd]1048        owl_editwin_key_right(e);
1049      } else {
1050        owl_editwin_delete_char(e);
[84027015]1051        /* if we did this ahead of the save point, adjust it. Changing
1052           by one is fine here because we're only removing an ASCII
1053           space. */
[47519e1b]1054        if (i < save) save--;
[7d4fbcd]1055      }
1056    } else {
1057      owl_editwin_key_right(e);
1058    }
1059  }
1060
1061  /* put cursor back at starting point */
[a0fbdee]1062  oe_restore_excursion(e, &x);
[a556caa]1063#endif
[7d4fbcd]1064}
1065
[cf83b7a]1066/* returns true if only whitespace remains */
[c9334b1]1067int owl_editwin_is_at_end(owl_editwin *e)
1068{
[a556caa]1069  return (only_whitespace(e->buff + e->index));
[217a43e]1070}
1071
[c9334b1]1072int owl_editwin_check_dotsend(owl_editwin *e)
1073{
[47519e1b]1074  char *p, *p_n, *p_p;
1075  gunichar c;
[7d4fbcd]1076
1077  if (!e->dotsend) return(0);
[47519e1b]1078
1079  p = g_utf8_find_prev_char(e->buff, e->buff + e->bufflen);
1080  p_n = g_utf8_find_next_char(p, NULL);
1081  p_p = g_utf8_find_prev_char(e->buff, p);
1082  c = g_utf8_get_char(p);
1083  while (p != NULL) {
1084    if (*p == '.'
1085        && p_p != NULL && (*p_p == '\n' || *p_p == '\r')
1086        && p_n != NULL && (*p_n == '\n' || *p_n == '\r')) {
1087      e->bufflen = p - e->buff;
1088      e->buff[e->bufflen] = '\0';
[7d4fbcd]1089      return(1);
1090    }
[47519e1b]1091    if (c != '\0' && !g_unichar_isspace(c)) return(0);
1092    p_n = p;
1093    p = p_p;
1094    c = g_utf8_get_char(p);
1095    p_p = g_utf8_find_prev_char(e->buff, p);
[7d4fbcd]1096  }
1097  return(0);
1098}
1099
[fac5463]1100void owl_editwin_post_process_char(owl_editwin *e, owl_input j)
[c9334b1]1101{
[a556caa]1102  /* XXX force a redisplay? */
[fac5463]1103  if ((j.ch==13 || j.ch==10) && owl_editwin_check_dotsend(e)) {
[7d4fbcd]1104    owl_command_editmulti_done(e);
1105    return;
1106  }
[e20d8179]1107  owl_editwin_redisplay(e, 0);
[7d4fbcd]1108}
1109
[fac5463]1110void _owl_editwin_process_char(owl_editwin *e, gunichar j)
[c9334b1]1111{
[bd1a1ae]1112  if (!(g_unichar_iscntrl(j) && (j != 10) && (j != 13)) || j==9 ) {
[7d4fbcd]1113    owl_editwin_insert_char(e, j);
1114  }
1115}
1116
[fac5463]1117
1118void owl_editwin_process_char(owl_editwin *e, owl_input j)
1119{
1120  if (j.ch == ERR) return;
1121  /* Ignore ncurses control characters. */
[e20d8179]1122  if (j.ch < 0x100) {
[fac5463]1123    _owl_editwin_process_char(e, j.uch);
1124  }
1125}
1126
[c9334b1]1127char *owl_editwin_get_text(owl_editwin *e)
1128{
[7d4fbcd]1129  return(e->buff+e->lock);
1130}
1131
[c9334b1]1132int owl_editwin_get_numlines(owl_editwin *e)
1133{
[7d4fbcd]1134  return(owl_text_num_lines(e->buff));
1135}
1136
[a556caa]1137int owl_editwin_get_echochar(owl_editwin *e) {
1138  return e->echochar;
1139}
[e20d8179]1140
1141void owl_editwin_set_goal_column(owl_editwin *e, int column)
1142{
1143  e->goal_column = column;
1144}
1145
1146int owl_editwin_get_goal_column(owl_editwin *e)
1147{
1148  return e->goal_column;
1149}
Note: See TracBrowser for help on using the repository browser.