source: editwin.c @ fac5463

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