source: editwin.c @ 2f21a41

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