source: editwin.c @ 8321cb7

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