source: editwin.c @ 3cc1582

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