source: editwin.c @ 19f765d

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