source: editwin.c @ 61abb18

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