source: editwin.c @ bd1a1ae

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