source: editwin.c @ c020e73

barnowl_perlaimdebianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since c020e73 was c020e73, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 13 years ago
Fixing an obscure wrapping bug that nelhage and I tracked down.
  • Property mode set to 100644
File size: 28.2 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)(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 x, y;
354  int i;
355  char *ptr1, *start;
356  gunichar c;
357
358  /* saving values */
359  x = e->buffx;
360  y = e->buffy;
361  start = e->buff + e->lock;
362
363  ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
364  ptr1 = g_utf8_find_prev_char(start, ptr1);
365
366  while (ptr1) {
367    c = g_utf8_get_char(ptr1);
368    if (owl_util_can_break_after(c)) {
369      if (c != ' ') {
370        i = ptr1 - e->buff;
371        _owl_editwin_set_xy_by_index(e, i);
372        _owl_editwin_insert_bytes(e, 1);
373        /* _owl_editwin_insert_bytes may move e->buff. */
374        ptr1 = e->buff + i;
375      }
376      *ptr1 = '\n';
377      return 0;
378    }
379    ptr1 = g_utf8_find_prev_char(start, ptr1);
380  }
381  return -1;
382}
383
384/* insert a character at the current point (shift later
385 * characters over)
386 */
387void owl_editwin_insert_char(owl_editwin *e, gunichar c)
388{
389  int z, i, ret, len;
390  char tmp[6];
391  memset(tmp, '\0', 6);
392
393  /* \r is \n */
394  if (c == '\r') {
395    c = '\n';
396  }
397
398  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
399    /* perhaps later this will change some state that allows the string
400       to be read */
401    return;
402  }
403
404  g_unichar_to_utf8(c, tmp);
405  len = strlen(tmp);
406
407  /* make sure there is enough memory for the new text */
408  if ((e->bufflen + len) > (e->allocated - 5)) {
409    _owl_editwin_addspace(e);
410  }
411
412  /* get the insertion point */
413  z = _owl_editwin_get_index_from_xy(e);
414
415  /* If we're going to insert at the last column do word wrapping, unless it's a \n */
416  if ((e->buffx + 1 == e->wrapcol) && (c != '\n')) {
417    ret = _owl_editwin_linewrap_word(e);
418    if (ret == -1) {
419      /* we couldn't wrap, insert a hard newline instead */
420      owl_editwin_insert_char(e, '\n');
421    }
422  }
423
424  /* shift all the other characters right */
425  if (z != e->bufflen) {
426    _owl_editwin_insert_bytes(e, len);
427  }
428
429  /* insert the new character */
430  for(i = 0; i < len; i++) {
431    e->buff[z + i] = tmp[i];
432  }
433
434  /* housekeeping */
435  e->bufflen += len;
436  e->buff[e->bufflen] = '\0';
437 
438  /* advance the cursor */
439  z += len;
440  _owl_editwin_set_xy_by_index(e, z);
441}
442
443/* overwrite the character at the current point with 'c' */
444void owl_editwin_overwrite_char(owl_editwin *e, gunichar c)
445{
446  int z, oldlen, newlen, i;
447  char tmp[6];
448  memset(tmp, '\0', 6);
449
450  /* \r is \n */
451  if (c == '\r') {
452    c = '\n';
453  }
454 
455  if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
456    /* perhaps later this will change some state that allows the string
457       to be read */
458    return;
459  }
460
461  g_unichar_to_utf8(c, tmp);
462  newlen = strlen(tmp);
463
464  z = _owl_editwin_get_index_from_xy(e);
465  {
466    char *t = g_utf8_find_next_char(e->buff + z, NULL);
467    oldlen = (t ? (t - (e->buff + z)) : 0);
468  }
469
470  /* only if we are at the end of the buffer do we create new space here */
471  if (z == e->bufflen) {
472    if ((e->bufflen+newlen) > (e->allocated-5)) {
473      _owl_editwin_addspace(e);
474    }
475  }
476  /* if not at the end of the buffer, adjust based in char size difference. */ 
477  else if (oldlen > newlen) {
478    _owl_editwin_remove_bytes(e, oldlen-newlen);
479  }
480  else /* oldlen < newlen */ {
481    _owl_editwin_insert_bytes(e, newlen-oldlen);
482  }
483  /* Overwrite the old char*/
484  for (i = 0; i < newlen; i++) {
485    e->buff[z+i] = tmp[i];
486  }
487       
488  /* housekeeping */
489  if (z == e->bufflen) {
490    e->bufflen += newlen;
491    e->buff[e->bufflen] = '\0';
492  }
493 
494  /* advance the cursor */
495  z += newlen;
496  _owl_editwin_set_xy_by_index(e, z);
497}
498
499/* delete the character at the current point, following chars
500 * shift left.
501 */ 
502void owl_editwin_delete_char(owl_editwin *e)
503{
504  int z;
505  char *p1, *p2;
506  gunichar c;
507
508  if (e->bufflen == 0) return;
509 
510  /* get the deletion point */
511  z = _owl_editwin_get_index_from_xy(e);
512
513  if (z == e->bufflen) return;
514
515  p1 = e->buff + z;
516  p2 = g_utf8_next_char(p1);
517  c = g_utf8_get_char(p2);
518  while (g_unichar_ismark(c)) {
519    p2 = g_utf8_next_char(p2);
520    c = g_utf8_get_char(p2);
521  }
522  _owl_editwin_remove_bytes(e, p2-p1);
523}
524
525/* Swap the character at point with the character at point-1 and
526 * advance the pointer.  If point is at beginning of buffer do
527 * nothing.  If point is after the last character swap point-1 with
528 * point-2.  (Behaves as observed in tcsh and emacs). 
529 */
530void owl_editwin_transpose_chars(owl_editwin *e)
531{
532  int z;
533  char *p1, *p2, *p3, *tmp;
534
535  if (e->bufflen == 0) return;
536 
537  /* get the cursor point */
538  z = _owl_editwin_get_index_from_xy(e);
539
540  if (z == e->bufflen) {
541    /* point is after last character */
542    z--;
543  } 
544
545  if (z - 1 < e->lock) {
546    /* point is at beginning of buffer, do nothing */
547    return;
548  }
549
550  /* Transpose two utf-8 unicode glyphs. */
551  p1 = e->buff + z;
552
553  p2 = g_utf8_find_next_char(p1, NULL);
554  while (p2 != NULL && g_unichar_ismark(g_utf8_get_char(p2))) {
555    p2 = g_utf8_find_next_char(p2, NULL);
556  }
557  if (p2 == NULL) return;
558
559  p3 = g_utf8_find_prev_char(e->buff, p1);
560  while (p3 != NULL && g_unichar_ismark(g_utf8_get_char(p3))) {
561    p3 = g_utf8_find_prev_char(p3, NULL);
562  }
563  if (p3 == NULL) return;
564
565  tmp = owl_malloc(p2 - p3 + 5);
566  *tmp = '\0';
567  strncat(tmp, p1, p2 - p1);
568  strncat(tmp, p3, p1 - p3);
569  strncpy(p3, tmp, p2 - p3);
570  owl_free(tmp);
571  _owl_editwin_set_xy_by_index(e, p3 - e->buff);
572}
573
574/* insert 'string' at the current point, later text is shifted
575 * right
576 */
577void owl_editwin_insert_string(owl_editwin *e, char *string)
578{
579  char *p;
580  gunichar c;
581  if (!g_utf8_validate(string, -1, NULL)) {
582    owl_function_debugmsg("owl_editwin_insert_string: received non-utf-8 string.");
583    return;
584  }
585  p = string;
586  c = g_utf8_get_char(p);
587  while (c) {
588    _owl_editwin_process_char(e, c);
589    p = g_utf8_next_char(p);
590    c = g_utf8_get_char(p);
591  }
592}
593
594/* write 'string' at the current point, overwriting text that is
595 * already there
596 */
597
598void owl_editwin_overwrite_string(owl_editwin *e, char *string)
599{
600  char *p;
601  gunichar c;
602
603  if (!g_utf8_validate(string, -1, NULL)) {
604    owl_function_debugmsg("owl_editwin_overwrite_string: received non-utf-8 string.");
605    return;
606  }
607  p = string;
608  c = g_utf8_get_char(p);
609  while (c) {
610    owl_editwin_overwrite_char(e, c);
611    p = g_utf8_next_char(p);
612    c = g_utf8_get_char(p);
613  }
614}
615
616/* get the index into e->buff for the current cursor
617 * position.
618 */
619int _owl_editwin_get_index_from_xy(owl_editwin *e)
620{
621  int i;
622  char *ptr1, *ptr2;
623  gunichar c;
624
625  if (e->bufflen == 0) return(0);
626 
627  /* first go to the yth line */
628  ptr1 = e->buff;
629  for (i = 0; i < e->buffy; i++) {
630    ptr2= strchr(ptr1, '\n');
631    if (!ptr2) {
632      /* we're already on the last line */
633      break;
634    }
635    ptr1 = ptr2 + 1;
636  }
637
638  /* now go to the xth cell */
639  ptr2 = ptr1;
640  i = 0;
641  while (ptr2 != NULL && i < e->buffx && (ptr2 - e->buff) < e->bufflen) {
642    c = g_utf8_get_char(ptr2);
643    i += (c == '\n' ? 1 : mk_wcwidth(c));
644    ptr2 = g_utf8_next_char(ptr2);
645  }
646  while(ptr2 != NULL && g_unichar_ismark(g_utf8_get_char(ptr2))) {
647    ptr2 = g_utf8_next_char(ptr2);
648  }
649  if (ptr2 == NULL) return e->bufflen;
650  return(ptr2 - e->buff);
651}
652
653/* We assume x,y are not set to point to a mid-char */
654gunichar _owl_editwin_get_char_at_xy(owl_editwin *e)
655{
656  return g_utf8_get_char(e->buff + _owl_editwin_get_index_from_xy(e));
657}
658
659
660void _owl_editwin_set_xy_by_index(owl_editwin *e, int index)
661{
662  char *ptr1, *ptr2, *target;
663  gunichar c;
664
665  e->buffx = 0;
666  e->buffy = 0;
667
668  ptr1 = e->buff;
669  target = ptr1 + index;
670  /* target sanitizing */
671  if ((target[0] & 0x80) && (~target[0] & 0x40)) {
672    /* middle of a utf-8 character, back up to previous character. */
673    target = g_utf8_find_prev_char(e->buff, target);
674  }
675  c = g_utf8_get_char(target);
676  while (g_unichar_ismark(c) && target > e->buff) {
677    /* Adjust the target off of combining characters and the like. */
678    target = g_utf8_find_prev_char(e->buff, target);
679    c = g_utf8_get_char(target);
680  }
681  /* If we start with a mark, something is wrong.*/
682  if (g_unichar_ismark(c)) return;
683
684  /* Now our target should be acceptable. */
685  ptr2 = strchr(ptr1, '\n');
686  while (ptr2 != NULL && ptr2 < target) {
687    e->buffy++;
688    ptr1 = ptr2 + 1;
689    ptr2 = strchr(ptr1, '\n');
690  }
691  ptr2 = ptr1;
692  while (ptr2 != NULL && ptr2 < target) {
693    c = g_utf8_get_char(ptr2);
694    e->buffx += mk_wcwidth(c);
695    ptr2 = g_utf8_next_char(ptr2);
696  }
697}
698
699int _owl_editwin_cursor_adjustment(owl_editwin *e)
700{
701  char *ptr1, *ptr2;
702  gunichar c;
703  int x, i;
704
705  /* Find line */
706  ptr1 = e->buff;
707  ptr2 = strchr(ptr1, '\n');
708  for (i = 0; ptr2 != NULL && i < e->buffy; i++) {
709    ptr1 = ptr2 + 1;
710    ptr2 = strchr(ptr1, '\n');
711  }
712  ptr2 = ptr1;
713
714  /* Find char */
715  x = 0;
716  while (ptr2 != NULL && x < e->buffx) {
717    if (*ptr2 == '\n') return 0;
718    c = g_utf8_get_char(ptr2);
719    x += mk_wcwidth(c);
720    ptr2 = g_utf8_next_char(ptr2);
721  }
722 
723  /* calculate x offset */
724  return x - e->buffx;
725}
726
727void owl_editwin_adjust_for_locktext(owl_editwin *e)
728{
729  /* if we happen to have the cursor over locked text
730   * move it to be out of the locktext region */
731  if (_owl_editwin_get_index_from_xy(e) < e->lock) {
732    _owl_editwin_set_xy_by_index(e, e->lock);
733  }
734}
735
736void owl_editwin_backspace(owl_editwin *e)
737{
738  /* delete the char before the current one
739   * and shift later chars left
740   */
741  if (_owl_editwin_get_index_from_xy(e) > e->lock) {
742    owl_editwin_key_left(e);
743    owl_editwin_delete_char(e);
744  }
745  owl_editwin_adjust_for_locktext(e);
746}
747
748void owl_editwin_key_up(owl_editwin *e)
749{
750  if (e->buffy > 0) e->buffy--;
751  if (e->buffx >= owl_editwin_get_numcells_on_line(e, e->buffy)) {
752    e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
753  }
754
755  /* do we need to scroll? */
756  if (e->buffy-e->topline < 0) {
757    e->topline-=e->winlines/2;
758  }
759
760  owl_editwin_adjust_for_locktext(e);
761}
762
763void owl_editwin_key_down(owl_editwin *e)
764{
765  /* move down if we can */
766  if (e->buffy+1 < owl_editwin_get_numlines(e)) e->buffy++;
767
768  /* if we're past the last character move back */
769  if (e->buffx >= owl_editwin_get_numcells_on_line(e, e->buffy)) {
770    e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
771  }
772
773  /* do we need to scroll? */
774  if (e->buffy-e->topline > e->winlines) {
775    e->topline+=e->winlines/2;
776  }
777
778  /* adjust for locktext */
779  owl_editwin_adjust_for_locktext(e);
780}
781
782void owl_editwin_key_left(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_prev_char(e->buff, p);
789  while (p && g_unichar_ismark(g_utf8_get_char(p))) {
790    p = g_utf8_find_prev_char(e->buff, p);
791  }
792  if (p == NULL) p = e->buff;
793  _owl_editwin_set_xy_by_index(e, p - e->buff);
794
795  if (e->buffy - e->topline < 0) {
796    e->topline -= e->winlines / 2;
797  }
798
799  /* make sure to avoid locktext */
800  owl_editwin_adjust_for_locktext(e);
801}
802
803void owl_editwin_key_right(owl_editwin *e)
804{
805  int i;
806  char * p;
807  i = _owl_editwin_get_index_from_xy(e);
808  p = e->buff + i;
809  p = g_utf8_find_next_char(p, NULL);
810  while (p && g_unichar_ismark(g_utf8_get_char(p))) {
811    p = g_utf8_find_next_char(p, NULL);
812  }
813  if (p == NULL) {
814    _owl_editwin_set_xy_by_index(e, e->bufflen);
815  }
816  else {
817    _owl_editwin_set_xy_by_index(e, p - e->buff);
818  }
819
820  /* do we need to scroll down? */
821  if (e->buffy - e->topline >= e->winlines) {
822    e->topline += e->winlines / 2;
823  }
824}
825
826void owl_editwin_move_to_nextword(owl_editwin *e)
827{
828  int i, x;
829  gunichar c = '\0';
830
831  /* if we're starting on a space, find the first non-space */
832  i=_owl_editwin_get_index_from_xy(e);
833  if (e->buff[i]==' ') {
834    for (x=i; x<e->bufflen; x++) {
835      if (e->buff[x]!=' ' && e->buff[x]!='\n') {
836        _owl_editwin_set_xy_by_index(e, x);
837        break;
838      }
839    }
840  }
841
842  /* find the next space, newline or end of line and go
843     there, if already at the end of the line, continue on to the next */
844  i=owl_editwin_get_numcells_on_line(e, e->buffy);
845  c = _owl_editwin_get_char_at_xy(e);
846  if (e->buffx < i) {
847    /* move right till end of line */
848    while (e->buffx < i) {
849      owl_editwin_key_right(e);
850      c = _owl_editwin_get_char_at_xy(e);
851      if (c == ' ') return;
852      if (e->buffx == i) return;
853    }
854  } else if (e->buffx == i) {
855    /* try to move down */
856    if (e->style==OWL_EDITWIN_STYLE_MULTILINE) {
857      if (e->buffy+1 < owl_editwin_get_numlines(e)) {
858        e->buffx=0;
859        e->buffy++;
860        owl_editwin_move_to_nextword(e);
861      }
862    }
863  }
864}
865
866/* go backwards to the last non-space character
867 */
868void owl_editwin_move_to_previousword(owl_editwin *e)
869{
870  int i;
871  gunichar c;
872  char *ptr1, *ptr2;
873
874  /* are we already at the beginning of the word? */
875  c = _owl_editwin_get_char_at_xy(e);
876  i = _owl_editwin_get_index_from_xy(e);
877  ptr1 = e->buff + i;
878  if (*ptr1 != ' ' && *ptr1 != '\n' && *ptr1 != '\0' ) {
879    ptr1 = g_utf8_find_prev_char(e->buff, ptr1);
880    c = g_utf8_get_char(ptr1);
881    if (c == ' ' || c == '\n') {
882      owl_editwin_key_left(e);     
883    }
884  }
885
886  /* are we starting on a space character? */
887  i = _owl_editwin_get_index_from_xy(e);
888  while (i > e->lock && (e->buff[i] == ' ' || e->buff[i] == '\n' || e->buff[i] == '\0')) {
889    /* find the first non-space */
890    owl_editwin_key_left(e);     
891    i = _owl_editwin_get_index_from_xy(e);
892  }
893
894  /* find the last non-space */
895  ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
896  while (ptr1 >= e->buff + e->lock) {
897    ptr2 = g_utf8_find_prev_char(e->buff, ptr1);
898    if (!ptr2) break;
899   
900    c = g_utf8_get_char(ptr2);
901    if (c == ' ' || c == '\n'){
902      break;
903    }
904    owl_editwin_key_left(e);
905    ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
906  }
907}
908
909
910void owl_editwin_delete_nextword(owl_editwin *e)
911{
912  char *ptr1, *start;
913  gunichar c;
914
915  if (e->bufflen==0) return;
916
917  start = ptr1 = e->buff + _owl_editwin_get_index_from_xy(e);
918  /* if we start out on a space character then jump past all the
919     spaces up first */
920  while (*ptr1 == ' ' || *ptr1 == '\n') {
921    ++ptr1;
922  }
923
924  /* then jump past the next word */
925 
926  while (ptr1 && ptr1 - e->buff < e->bufflen) {
927    c = g_utf8_get_char(ptr1);
928    if (c == ' ' || c == '\n' || c == '\0') break;
929    ptr1 = g_utf8_find_next_char(ptr1, NULL);
930  }
931
932  if (ptr1) { /* We broke on a space, */
933    ptr1 = g_utf8_find_next_char(ptr1, NULL);
934    if (ptr1) { /* and there's a character after it, */
935      /* nuke everything back to our starting point. */
936      _owl_editwin_remove_bytes(e, ptr1 - start);
937      return;
938    }
939  }
940 
941  /* If we get here, we ran out of string, drop what's left. */
942  *start = '\0';
943  e->bufflen = start - e->buff;
944}
945
946void owl_editwin_delete_previousword(owl_editwin *e)
947{
948  /* go backwards to the last non-space character, then delete chars */
949  int startpos, endpos;
950
951  startpos = _owl_editwin_get_index_from_xy(e);
952  owl_editwin_move_to_previousword(e);
953  endpos = _owl_editwin_get_index_from_xy(e);
954  _owl_editwin_remove_bytes(e, startpos-endpos);
955}
956
957void owl_editwin_delete_to_endofline(owl_editwin *e)
958{
959  int i;
960
961  if (owl_editwin_get_numchars_on_line(e, e->buffy) > e->buffx) {
962    /* normal line */
963    i=_owl_editwin_get_index_from_xy(e);
964    while(i < e->bufflen) {
965      if (e->buff[i]!='\n') {
966        owl_editwin_delete_char(e);
967      } else if ((e->buff[i]=='\n') && (i==e->bufflen-1)) {
968        owl_editwin_delete_char(e);
969      } else {
970        return;
971      }
972    }
973  } else if (e->buffy+1 < owl_editwin_get_numlines(e)) {
974    /* line with cursor at the end but not on very last line */
975    owl_editwin_key_right(e);
976    owl_editwin_backspace(e);
977  }
978}
979
980void owl_editwin_move_to_line_end(owl_editwin *e)
981{
982  e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
983}
984
985void owl_editwin_move_to_line_start(owl_editwin *e)
986{
987  e->buffx=0;
988  owl_editwin_adjust_for_locktext(e);
989}
990
991void owl_editwin_move_to_end(owl_editwin *e)
992{
993  /* go to last char */
994  e->buffy=owl_editwin_get_numlines(e)-1;
995  e->buffx=owl_editwin_get_numcells_on_line(e, e->buffy);
996  owl_editwin_key_right(e);
997
998  /* do we need to scroll? */
999  /*
1000  if (e->buffy-e->topline > e->winlines) {
1001    e->topline+=e->winlines/2;
1002  }
1003  */
1004  owl_editwin_recenter(e);
1005}
1006
1007void owl_editwin_move_to_top(owl_editwin *e)
1008{
1009  _owl_editwin_set_xy_by_index(e, 0);
1010
1011  /* do we need to scroll? */
1012  e->topline=0;
1013
1014  owl_editwin_adjust_for_locktext(e);
1015}
1016
1017void owl_editwin_fill_paragraph(owl_editwin *e)
1018{
1019  int i, save;
1020
1021  /* save our starting point */
1022  save=_owl_editwin_get_index_from_xy(e);
1023
1024  /* scan back to the beginning of this paragraph */
1025  for (i=save; i>=e->lock; i--) {
1026    if ( (i<=e->lock) ||
1027         ((e->buff[i]=='\n') && (e->buff[i-1]=='\n'))) {
1028      _owl_editwin_set_xy_by_index(e, i+1);
1029      break;
1030    }
1031  }
1032
1033  /* main loop */
1034  while (1) {
1035    i = _owl_editwin_get_index_from_xy(e);
1036
1037    /* bail if we hit the end of the buffer */
1038    if (i >= e->bufflen || e->buff[i] == '\0') break;
1039
1040    /* bail if we hit the end of the paragraph */
1041    if (e->buff[i] == '\n' && e->buff[i+1] == '\n') break;
1042
1043    /* if we've travelled too far, linewrap */
1044    if ((e->buffx) >= e->fillcol) {
1045      int len = e->bufflen;
1046      _owl_editwin_linewrap_word(e);
1047      /* we may have added a character. */
1048      if (i < save) save += e->bufflen - len;
1049      _owl_editwin_set_xy_by_index(e, i);
1050    }
1051
1052    /* did we hit the end of a line too soon? */
1053    /* asedeno: Here we replace a newline with a space. We may want to
1054       consider removing the space if the characters to either side
1055       are CJK ideograms.*/
1056    i = _owl_editwin_get_index_from_xy(e);
1057    if (e->buff[i] == '\n' && e->buffx < e->fillcol - 1) {
1058      /* ********* we need to make sure we don't pull in a word that's too long ***********/
1059      e->buff[i]=' ';
1060    }
1061
1062    /* fix spacing */
1063    i = _owl_editwin_get_index_from_xy(e);
1064    if (e->buff[i] == ' ' && e->buff[i+1] == ' ') {
1065      if (e->buff[i-1] == '.' || e->buff[i-1] == '!' || e->buff[i-1] == '?') {
1066        owl_editwin_key_right(e);
1067      } else {
1068        owl_editwin_delete_char(e);
1069        /* if we did this ahead of the save point, adjust it. Changing
1070           by one is fine here because we're only removing an ASCII
1071           space. */
1072        if (i < save) save--;
1073      }
1074    } else {
1075      owl_editwin_key_right(e);
1076    }
1077  }
1078
1079  /* put cursor back at starting point */
1080  _owl_editwin_set_xy_by_index(e, save);
1081
1082  /* do we need to scroll? */
1083  if (e->buffy-e->topline < 0) {
1084    e->topline-=e->winlines/2;
1085  }
1086}
1087
1088/* returns true if only whitespace remains */
1089int owl_editwin_is_at_end(owl_editwin *e)
1090{
1091  int cur=_owl_editwin_get_index_from_xy(e);
1092  return (only_whitespace(e->buff+cur));
1093}
1094
1095int owl_editwin_check_dotsend(owl_editwin *e)
1096{
1097  char *p, *p_n, *p_p;
1098  gunichar c;
1099
1100  if (!e->dotsend) return(0);
1101
1102  p = g_utf8_find_prev_char(e->buff, e->buff + e->bufflen);
1103  p_n = g_utf8_find_next_char(p, NULL);
1104  p_p = g_utf8_find_prev_char(e->buff, p);
1105  c = g_utf8_get_char(p);
1106  while (p != NULL) {
1107    if (*p == '.'
1108        && p_p != NULL && (*p_p == '\n' || *p_p == '\r')
1109        && p_n != NULL && (*p_n == '\n' || *p_n == '\r')) {
1110      e->bufflen = p - e->buff;
1111      e->buff[e->bufflen] = '\0';
1112      return(1);
1113    }
1114    if (c != '\0' && !g_unichar_isspace(c)) return(0);
1115    p_n = p;
1116    p = p_p;
1117    c = g_utf8_get_char(p);
1118    p_p = g_utf8_find_prev_char(e->buff, p);
1119  }
1120  return(0);
1121}
1122
1123void owl_editwin_post_process_char(owl_editwin *e, owl_input j)
1124{
1125  /* check if we need to scroll down */
1126  if (e->buffy-e->topline >= e->winlines) {
1127    e->topline+=e->winlines/2;
1128  }
1129  if ((j.ch==13 || j.ch==10) && owl_editwin_check_dotsend(e)) {
1130    owl_command_editmulti_done(e);
1131    return;
1132  }
1133  owl_editwin_redisplay(e, 0); 
1134}
1135
1136void _owl_editwin_process_char(owl_editwin *e, gunichar j)
1137{
1138  if (!(g_unichar_iscntrl(j) && (j != 10) && (j != 13))) {
1139    owl_editwin_insert_char(e, j);
1140  }
1141}
1142
1143
1144void owl_editwin_process_char(owl_editwin *e, owl_input j)
1145{
1146  if (j.ch == ERR) return;
1147  /* Ignore ncurses control characters. */
1148  if (j.ch < 0x100) { 
1149    _owl_editwin_process_char(e, j.uch);
1150  }
1151}
1152
1153char *owl_editwin_get_text(owl_editwin *e)
1154{
1155  return(e->buff+e->lock);
1156}
1157
1158int owl_editwin_get_numchars_on_line(owl_editwin *e, int line)
1159{
1160  int i;
1161  char *ptr1, *ptr2;
1162
1163  if (e->bufflen==0) return(0);
1164 
1165  /* first go to the yth line */
1166  ptr1=e->buff;
1167  for (i=0; i<line; i++) {
1168    ptr2=strchr(ptr1, '\n');
1169    if (!ptr2) {
1170      /* we're already on the last line */
1171      return(0);
1172    }
1173    ptr1=ptr2+1;
1174  }
1175
1176  /* now count characters */
1177  i = 0;
1178  ptr2 = ptr1;
1179  while (ptr2 - e->buff < e->bufflen
1180         && *ptr2 != '\n') {
1181    ++i;
1182    ptr2 = g_utf8_next_char(ptr2);
1183  }
1184  return i;
1185}
1186
1187int owl_editwin_get_numcells_on_line(owl_editwin *e, int line)
1188{
1189  int i;
1190  char *ptr1, *ptr2;
1191  gunichar c;
1192
1193  if (e->bufflen==0) return(0);
1194 
1195  /* first go to the yth line */
1196  ptr1=e->buff;
1197  for (i=0; i<line; i++) {
1198    ptr2=strchr(ptr1, '\n');
1199    if (!ptr2) {
1200      /* we're already on the last line */
1201      return(0);
1202    }
1203    ptr1=ptr2+1;
1204  }
1205
1206  /* now count cells */
1207  i = 0;
1208  ptr2 = ptr1;
1209  while (ptr2 - e->buff < e->bufflen
1210         && *ptr2 != '\n') {
1211    c = g_utf8_get_char(ptr2);
1212    i += mk_wcwidth(c);
1213    ptr2 = g_utf8_next_char(ptr2);
1214  }
1215  return i;
1216}
1217
1218int owl_editwin_get_numlines(owl_editwin *e)
1219{
1220  return(owl_text_num_lines(e->buff));
1221}
1222
Note: See TracBrowser for help on using the repository browser.