source: editwin.c @ 98f1e69

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