source: editwin.c @ a556caa

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