source: editwin.c @ 61abb18

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