source: editwin.c @ e23eb2b

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