source: editwin.c @ 3dcccba

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