source: editwin.c @ 38a5cc1

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