source: editwin.c @ a45786e

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