source: editwin.c @ a0fbdee

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