source: editwin.c @ e20d8179

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