source: editwin.c @ 521bc84

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