source: editwin.c @ e0ffe77

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