source: editwin.c @ 37f9818

release-1.10release-1.7release-1.8release-1.9
Last change on this file since 37f9818 was 4e33cb2, checked in by David Benjamin <davidben@mit.edu>, 14 years ago
Punt a lot of needrefreshes Move the actual needrefreshes into the functions actually dealing with curses. This will, of course, later get moved out of the paint events and no one will call it. But that's later.
  • Property mode set to 100644
File size: 30.3 KB
RevLine 
[7d4fbcd]1#include "owl.h"
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
[10b866d]5#include <ctype.h>
[7d4fbcd]6
[ebf0128]7#define VALID_EXCURSION (0x9a2b4729)
8
[a88f35a]9typedef struct _owl_editwin_excursion { /*noproto*/
[ebf0128]10  int valid;
11  int index;
[16cfd12a]12  int mark;
[ebf0128]13  int goal_column;
14  int lock;
[a88f35a]15  struct _owl_editwin_excursion *next;
[ebf0128]16} oe_excursion;
17
[a556caa]18struct _owl_editwin { /*noproto*/
19  char *buff;
20  owl_history *hist;
21  int bufflen;
22  int allocated;
23  int index;
[16cfd12a]24  int mark;
[a60edf2]25  char *killbuf;
[a556caa]26  int goal_column;
27  int topindex;
[ebf0128]28  int cursorx;
[a556caa]29  int winlines, wincols, fillcol, wrapcol;
30  WINDOW *curswin;
31  int style;
32  int lock;
33  int dotsend;
34  int echochar;
[ebf0128]35  oe_excursion *excursions;
[a556caa]36
37  void (*callback)(struct _owl_editwin*);
[1b1cd2c]38  void (*destroy_cbdata)(void *);
[a556caa]39  void *cbdata;
40};
41
[e20d8179]42static void oe_reframe(owl_editwin *e);
[bab52da]43static void oe_save_excursion(owl_editwin *e, oe_excursion *x);
[ebf0128]44static void oe_release_excursion(owl_editwin *e, oe_excursion *x);
[bab52da]45static void oe_restore_excursion(owl_editwin *e, oe_excursion *x);
[a60edf2]46static void oe_restore_mark_only(owl_editwin *e, oe_excursion *x);
[ebf0128]47static int oe_char_width(gunichar c, int column);
[16cfd12a]48static int oe_region_width(owl_editwin *e, int start, int end, int width);
[7149832]49static int oe_find_display_line(owl_editwin *e, int *x, int index, int *hard);
[ebf0128]50static void oe_insert_char(owl_editwin *e, gunichar c);
[d625cfd]51static int owl_editwin_limit_maxcols(int width, int cols);
[bab52da]52static int owl_editwin_check_dotsend(owl_editwin *e);
[e19eb97]53static int owl_editwin_is_char_in(owl_editwin *e, const char *set);
[bab52da]54static gunichar owl_editwin_get_char_at_point(owl_editwin *e);
[e19eb97]55static int owl_editwin_replace_internal(owl_editwin *e, int replace, const char *s);
56static const char *oe_copy_buf(owl_editwin *e, const char *buf, int len);
[a60edf2]57static int oe_copy_region(owl_editwin *e);
[77f605d]58static char *oe_chunk(owl_editwin *e, int start, int end);
[1b1cd2c]59static void oe_destroy_cbdata(owl_editwin *e);
[bab52da]60
[5b5f3e6]61#define INCR 4096
[7d4fbcd]62
[a556caa]63#define WHITESPACE " \n\t"
64
[38cc669]65static owl_editwin *owl_editwin_allocate(void)
[bab52da]66{
[8321cb7]67  owl_editwin *e;
68  e = owl_malloc(sizeof(owl_editwin));
69  memset(e, 0, sizeof(*e));
70  return e;
[a556caa]71}
72
[30bb10a]73void owl_editwin_delete(owl_editwin *e)
[6211c76]74{
75  owl_free(e->buff);
76  owl_free(e->killbuf);
77  /* just in case someone forgot to clean up */
78  while (e->excursions) {
79    oe_release_excursion(e, e->excursions);
80  }
[38cc669]81  oe_destroy_cbdata(e);
[6211c76]82
83  owl_free(e);
84}
85
[bab52da]86static inline void oe_set_index(owl_editwin *e, int index)
87{
[ebf0128]88  if (index != e->index) {
89    e->goal_column = -1;
90    e->cursorx = -1;
91  }
[521bc84]92  e->index = index;
93}
94
[7f0c26f]95static inline void oe_set_mark(owl_editwin *e, int mark)
96{
97  e->mark = mark;
98}
99
100void owl_editwin_set_mark(owl_editwin *e)
101{
102  oe_set_mark(e, e->index);
103  /* owl_function_makemsg("Mark set."); */
104}
105
[38cc669]106static void _owl_editwin_init(owl_editwin *e,
107                              WINDOW *win,
108                              int winlines,
109                              int wincols,
110                              int style,
111                              owl_history *hist)
[c9334b1]112{
[e20d8179]113  e->buff=owl_malloc(INCR);
[7d4fbcd]114  e->buff[0]='\0';
115  e->bufflen=0;
[10b866d]116  e->hist=hist;
[7d4fbcd]117  e->allocated=INCR;
[521bc84]118  oe_set_index(e, 0);
[7f0c26f]119  oe_set_mark(e, -1);
[a60edf2]120  if (e->killbuf != NULL)
[27f6487]121    owl_free(e->killbuf);
[a60edf2]122  e->killbuf = NULL;
[a556caa]123  e->goal_column = -1;
[ebf0128]124  e->cursorx = -1;
125  e->topindex = 0;
126  e->excursions = NULL;
[7d4fbcd]127  e->style=style;
128  if ((style!=OWL_EDITWIN_STYLE_MULTILINE) &&
129      (style!=OWL_EDITWIN_STYLE_ONELINE)) {
130    e->style=OWL_EDITWIN_STYLE_MULTILINE;
131  }
[9d7a720]132  owl_editwin_set_curswin(e, win, winlines, wincols);
[7d4fbcd]133  e->lock=0;
134  e->dotsend=0;
[c9334b1]135  e->echochar='\0';
[e74c01c]136
[7d4fbcd]137  if (win) werase(win);
138}
139
[38cc669]140owl_editwin *owl_editwin_new(WINDOW *win, int winlines, int wincols, int style, owl_history *hist)
141{
142  owl_editwin *e = owl_editwin_allocate();
143
144  _owl_editwin_init(e, win, winlines, wincols, style, hist);
145  return e;
146}
147
[c9334b1]148void owl_editwin_set_curswin(owl_editwin *e, WINDOW *w, int winlines, int wincols)
149{
[7d4fbcd]150  e->curswin=w;
151  e->winlines=winlines;
152  e->wincols=wincols;
[9a6cc40]153  e->fillcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxfillcols(&g));
[9d7a720]154  if (e->style == OWL_EDITWIN_STYLE_MULTILINE)
155    e->wrapcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxwrapcols(&g));
156  else
157    e->wrapcol = 0;
[7d4fbcd]158}
159
[c9334b1]160/* echo the character 'ch' for each normal character keystroke,
161 * excepting locktext.  This is useful for entering passwords etc.  If
162 * ch=='\0' characters are echo'd normally
163 */
164void owl_editwin_set_echochar(owl_editwin *e, int ch)
165{
166  e->echochar=ch;
167}
168
169WINDOW *owl_editwin_get_curswin(owl_editwin *e)
170{
[060b3b4]171  return(e->curswin);
[7d4fbcd]172}
173
[c9334b1]174owl_history *owl_editwin_get_history(owl_editwin *e)
175{
[060b3b4]176  return(e->hist);
[10b866d]177}
178
[c9334b1]179void owl_editwin_set_dotsend(owl_editwin *e)
180{
[7d4fbcd]181  e->dotsend=1;
182}
183
[bab52da]184void owl_editwin_set_callback(owl_editwin *e, void (*cb)(owl_editwin*))
185{
[e74c01c]186  e->callback = cb;
187}
188
[bab52da]189void (*owl_editwin_get_callback(owl_editwin *e))(owl_editwin*)
190{
[e74c01c]191  return e->callback;
192}
193
[1b1cd2c]194static void oe_destroy_cbdata(owl_editwin *e) {
195  if (e->destroy_cbdata)
196    e->destroy_cbdata(e->cbdata);
197  e->cbdata = NULL;
198  e->destroy_cbdata = NULL;
199}
200
201void owl_editwin_set_cbdata(owl_editwin *e, void *data, void (*destroy)(void *))
[bab52da]202{
[1b1cd2c]203  oe_destroy_cbdata(e);
[e74c01c]204  e->cbdata = data;
[1b1cd2c]205  e->destroy_cbdata = destroy;
[e74c01c]206}
207
[a556caa]208void *owl_editwin_get_cbdata(owl_editwin *e) {
[e74c01c]209  return e->cbdata;
210}
211
212void owl_editwin_do_callback(owl_editwin *e) {
213  void (*cb)(owl_editwin*);
214  cb=owl_editwin_get_callback(e);
215  if(!cb) {
216    owl_function_error("Internal error: No editwin callback!");
217  } else {
[af1920fd]218    /* owl_function_error("text: |%s|", owl_editwin_get_text(e)); */
[e74c01c]219    cb(e);
220  }
221}
222
[d625cfd]223static int owl_editwin_limit_maxcols(int width, int cols)
[c9334b1]224{
[d625cfd]225  if (cols == 0)
226    return width;
227  return cols;
[d36f2cb]228}
229
[c9334b1]230/* set text to be 'locked in' at the beginning of the buffer, any
231 * previous text (including locked text) will be overwritten
232 */
[e19eb97]233void owl_editwin_set_locktext(owl_editwin *e, const char *text)
[c9334b1]234{
[521bc84]235  oe_set_index(e, 0);
[5b5f3e6]236  e->lock = 0;
237  owl_editwin_replace(e, e->bufflen, text);
238  e->buff[e->bufflen] = 0;
239  e->lock=e->bufflen;
[521bc84]240  oe_set_index(e, e->lock);
[2ee9e8d]241  owl_editwin_redisplay(e);
[7d4fbcd]242}
243
[c9334b1]244int owl_editwin_get_style(owl_editwin *e)
245{
[7d4fbcd]246  return(e->style);
247}
248
[c9334b1]249/* clear all text except for locktext and put the cursor at the
250 * beginning
251 */
252void owl_editwin_clear(owl_editwin *e)
253{
254
[6073462]255  int lock = e->lock;
[10b866d]256  int dotsend=e->dotsend;
[7d4fbcd]257  char *locktext=NULL;
[cc6f009]258  char echochar=e->echochar;
[10b866d]259
[6073462]260  if (lock > 0) {
[5b5f3e6]261    locktext = owl_malloc(lock+1);
262    strncpy(locktext, e->buff, lock);
263    locktext[lock] = 0;
[7d4fbcd]264  }
265
266  owl_free(e->buff);
[38cc669]267  _owl_editwin_init(e, e->curswin, e->winlines, e->wincols, e->style, e->hist);
[7d4fbcd]268
269  if (lock > 0) {
270    owl_editwin_set_locktext(e, locktext);
271  }
[10b866d]272  if (dotsend) {
273    owl_editwin_set_dotsend(e);
274  }
[cc6f009]275  if (echochar) {
276    owl_editwin_set_echochar(e, echochar);
277  }
[7d4fbcd]278
[5b5f3e6]279  if (locktext)
280    owl_free(locktext);
[6073462]281
[521bc84]282  oe_set_index(e, lock);
[7d4fbcd]283}
284
[c9334b1]285void owl_editwin_recenter(owl_editwin *e)
286{
[a556caa]287  e->topindex = -1;
288}
[e20d8179]289
[a0fbdee]290static void oe_save_excursion(owl_editwin *e, oe_excursion *x)
291{
292  x->index = e->index;
[7f0c26f]293  x->mark = e->mark;
[a0fbdee]294  x->goal_column = e->goal_column;
295  x->lock = e->lock;
[ebf0128]296
297  x->valid = VALID_EXCURSION;
298  x->next = e->excursions;
299  e->excursions = x;
300}
301
302static void oe_release_excursion(owl_editwin *e, oe_excursion *x)
303{
[a85d225]304  oe_excursion **px;
[ebf0128]305
306  x->valid = 0;
[a85d225]307  for (px = &e->excursions; *px != NULL; px = &(*px)->next)
308    if (*px == x) {
309      *px = x->next;
310      return;
311    }
312  abort();
[a0fbdee]313}
314
315static void oe_restore_excursion(owl_editwin *e, oe_excursion *x)
316{
[ebf0128]317  if (x->valid == VALID_EXCURSION) {
318    oe_set_index(e, x->index);
319    e->goal_column = x->goal_column;
[7f0c26f]320    e->mark = x->mark;
[ebf0128]321    e->lock = x->lock;
322
323    oe_release_excursion(e, x);
324  }
[a0fbdee]325}
326
[a60edf2]327static void oe_restore_mark_only(owl_editwin *e, oe_excursion *x)
328{
329  if (x->valid == VALID_EXCURSION) {
330    e->mark = x->mark;
331
332    oe_release_excursion(e, x);
333  }
334}
335
[a88f35a]336/* External interface to oe_save_excursion */
337owl_editwin_excursion *owl_editwin_begin_excursion(owl_editwin *e)
338{
339  owl_editwin_excursion *x = owl_malloc(sizeof *x);
340  oe_save_excursion(e, x);
341  return x;
342}
343
344void owl_editwin_end_excursion(owl_editwin *e, owl_editwin_excursion *x)
345{
346  oe_restore_excursion(e, x);
347  owl_free(x);
348}
349
[e19eb97]350static inline const char *oe_next_point(owl_editwin *e, const char *p)
[e20d8179]351{
[e19eb97]352  const char *boundary = e->buff + e->bufflen + 1;
353  const char *q;
[e20d8179]354
355  q = g_utf8_find_next_char(p, boundary);
356  while (q && g_unichar_ismark(g_utf8_get_char(q)))
357    q = g_utf8_find_next_char(q, boundary);
358
359  if (q == p)
360    return NULL;
361  return q;
362}
363
[e19eb97]364static inline const char *oe_prev_point(owl_editwin *e, const char *p)
[e20d8179]365{
[e19eb97]366  const char *boundary = e->buff + e->lock;
[e20d8179]367
368  p = g_utf8_find_prev_char(boundary, p);
369  while (p && g_unichar_ismark(g_utf8_get_char(p)))
370    p = g_utf8_find_prev_char(boundary, p);
371
372  return p;
373}
374
[ebf0128]375static int oe_char_width(gunichar c, int column)
376{
377  int cw;
378
379  if (c == 9) /* TAB */
380    return TABSIZE - column % TABSIZE;
381
382  cw = mk_wcwidth(c);
383
384  if (cw < 0) /* control characters */
385    cw = 0;
386
387  return cw;
388}
389
[7149832]390static int oe_find_display_line(owl_editwin *e, int *x, int index, int *hard)
[19f765d]391{
392  int width = 0, cw;
[ebf0128]393  gunichar c;
[e19eb97]394  const char *p;
[19f765d]395
[77d4402]396  while(1) {
397    /* note the position of the dot */
[2021bea]398    if (x != NULL && index == e->index && width < e->wincols)
[19f765d]399      *x = width;
[77d4402]400
[19f765d]401    /* get the current character */
402    c = g_utf8_get_char(e->buff + index);
403
404    /* figure out how wide it is */
[ebf0128]405    cw = oe_char_width(c, width);
[19f765d]406
[7ce30a9]407    if (width + cw > e->wincols - 1) {
[77d4402]408      if (x != NULL && *x == width)
409        *x = -1;
[7149832]410      if (hard != NULL) *hard = 0;
[19f765d]411      break;
[77d4402]412    }
[19f765d]413    width += cw;
414
415    if (c == '\n') {
[77d4402]416      if (width < e->wincols)
417        ++index; /* skip the newline */
[7149832]418      if (hard != NULL) *hard = 1;
[19f765d]419      break;
420    }
421
422    /* find the next character */
423    p = oe_next_point(e, e->buff + index);
424    if (p == NULL) { /* we ran off the end */
425      if (x != NULL && e->index > index)
426        *x = width + 1;
[7149832]427      if (hard != NULL) *hard = 1;
[19f765d]428      break;
429    }
430    index = p - e->buff;
[cedc95c]431
[19f765d]432  }
433  return index;
434}
435
[e20d8179]436static void oe_reframe(owl_editwin *e) {
[cedc95c]437  oe_excursion x;
[460fbe8]438  int goal = 1 + e->winlines / 2;
[cedc95c]439  int index;
440  int count = 0;
441  int n, i;
442  int last;
443
444  oe_save_excursion(e, &x);
445  /* step back line-by-line through the buffer until we have >= goal lines of
446     display text */
447  e->lock = 0; /* we can (must) tread on the locktext */
448
449  last = -1;
450  while (count < goal) {
451    index = e->index;
452    owl_editwin_move_to_beginning_of_line(e);
453    if (last == e->index)
454      break;
455    last = e->index;
456    for (n = 0, i = e->index; i < index; n++)
[7149832]457      i = oe_find_display_line(e, NULL, i, NULL);
[cedc95c]458    count += n == 0 ? 1 : n;
459    if (count < goal)
460      owl_editwin_point_move(e, -1);
461  }
462
463  e->topindex = e->index;
[521bc84]464  /* if we overshot, backtrack */
465  for (n = 0; n < (count - goal); n++)
[7149832]466    e->topindex = oe_find_display_line(e, NULL, e->topindex, NULL);
[cedc95c]467
468  oe_restore_excursion(e, &x);
[7d4fbcd]469}
470
[3e36085]471static void oe_addnec(owl_editwin *e, int count)
472{
473  int i;
474
475  for (i = 0; i < count; i++)
476    waddch(e->curswin, e->echochar);
477}
478
479static void oe_mvaddnec(owl_editwin *e, int y, int x, int count)
480{
481  wmove(e->curswin, y, x);
482  oe_addnec(e, count);
483}
484
[c9334b1]485/* regenerate the text on the curses window */
[2ee9e8d]486void owl_editwin_redisplay(owl_editwin *e)
[c9334b1]487{
[7149832]488  int x = -1, y = -1, t, hard;
[77d4402]489  int line, index, lineindex, times = 0;
[7d4fbcd]490
[bd1a1ae]491  do {
[cedc95c]492    werase(e->curswin);
[36a16fc]493
494    if (e->topindex == -1 || e->index < e->topindex)
[e20d8179]495      oe_reframe(e);
496
[bd1a1ae]497    line = 0;
498    index = e->topindex;
499    while(line < e->winlines) {
500      lineindex = index;
[19f765d]501      t = -1;
[7149832]502      index = oe_find_display_line(e, &t, lineindex, &hard);
[19f765d]503      if (x == -1 && t != -1)
504        x = t, y = line;
[3e36085]505      if (index - lineindex) {
506        if (!e->echochar)
507          mvwaddnstr(e->curswin, line, 0,
508                     e->buff + lineindex,
509                     index - lineindex);
510        else {
511          if(lineindex < e->lock) {
512            mvwaddnstr(e->curswin, line, 0,
513                       e->buff + lineindex,
514                       MIN(index - lineindex,
515                           e->lock - lineindex));
516            if (e->lock < index)
517              oe_addnec(e,
518                        oe_region_width(e, e->lock, index,
519                                        oe_region_width(e, lineindex, e->lock, 0)));
520          } else
[7141d75]521            oe_mvaddnec(e, line, 0, oe_region_width(e, lineindex, index, 0));
[3e36085]522        }
[7149832]523        if (!hard)
524          waddch(e->curswin, '\\');
[3e36085]525      }
[bd1a1ae]526      line++;
[a556caa]527    }
[19f765d]528    if (x == -1)
[bd1a1ae]529        e->topindex = -1; /* force a reframe */
[77d4402]530    times++;
531  } while(x == -1 && times < 3);
[e20d8179]532
[19f765d]533  wmove(e->curswin, y, x);
[ebf0128]534  e->cursorx = x;
[4e33cb2]535  owl_global_set_needrefresh(&g);
[7d4fbcd]536}
537
[7f0c26f]538static inline void oe_fixup(int *target, int start, int end, int change) {
539  if (*target > start) {
[0d9c90c]540    if (*target <= end)
[8459609]541      *target = end + change;
[7f0c26f]542    else
543      *target += change;
544  }
545}
546
[e19eb97]547int owl_editwin_replace_region(owl_editwin *e, const char *s)
[a88f35a]548{
549  oe_excursion x;
550  int ret;
[6e58ff2]551
552  if (e->mark == -1) {
553    owl_function_error("The mark is unset, there is no region to replace.");
554    return 0;
555  }
556
[5ebc202]557  oe_save_excursion(e, &x);
[a88f35a]558
559  if(e->index > e->mark) {
560    owl_editwin_exchange_point_and_mark(e);
561  }
562
563  ret = owl_editwin_replace_internal(e, e->mark - e->index, s);
564
565  oe_restore_excursion(e, &x);
566
567  return ret;
568}
569
[19a023f]570/* replace 'replace' characters at the point with s, returning the change in size */
[e19eb97]571int owl_editwin_replace(owl_editwin *e, int replace, const char *s)
[ebf0128]572{
[19a023f]573  int start, end, i;
[e19eb97]574  const char *p;
[e9bb404]575
[5b5f3e6]576  if (!g_utf8_validate(s, -1, NULL)) {
577    owl_function_debugmsg("owl_editwin_insert_string: received non-utf-8 string.");
[ebf0128]578    return 0;
[47519e1b]579  }
580
[5b5f3e6]581  start = e->index;
582  for (i = 0, p = e->buff + start; i < replace && p != NULL; i++)
583    p = oe_next_point(e, p);
584  if (p != NULL)
585    end = p - e->buff;
586  else
587    end = e->bufflen;
588
[19a023f]589  return owl_editwin_replace_internal(e, end - start, s);
590}
591
[e19eb97]592static int owl_editwin_replace_internal(owl_editwin *e, int replace, const char *s)
[19a023f]593{
594  int start, end, free, need, size, change;
595  oe_excursion *x;
596
597  start = e->index;
598  end   = start + replace;
599
[5b5f3e6]600  free = e->allocated - e->bufflen + end - start;
601
602  need = strlen(s) - free;
603  if (need > 0) {
604    size = e->allocated + need + INCR - (need % INCR);
[b644688]605    e->buff = owl_realloc(e->buff, size);
[5b5f3e6]606    e->allocated = size;
[47519e1b]607  }
[e9bb404]608
[5b5f3e6]609  memmove(e->buff + start + strlen(s), e->buff + end, e->bufflen + 1 - end);
610  memcpy(e->buff + start, s, strlen(s));
[ebf0128]611  change = start - end + strlen(s);
612  e->bufflen += change;
[5b5f3e6]613  e->index += strlen(s);
[ebf0128]614
[7f0c26f]615  /* fix up the mark */
[3e36085]616  oe_fixup(&e->mark, start, end, change);
617  oe_fixup(&e->topindex, start, end, change);
[ebf0128]618  /* fix up any saved points after the replaced area */
[7f0c26f]619  for (x = e->excursions; x != NULL; x = x->next) {
620    oe_fixup(&x->index, start, end, change);
[3e36085]621    oe_fixup(&x->mark, start, end, change);
[7f0c26f]622  }
[ebf0128]623
[c471e85]624  /* recenter if needed */
625  if (start <= e->topindex)
626    owl_editwin_recenter(e);
627
[ebf0128]628  return change;
[47519e1b]629}
630
[c9334b1]631/* linewrap the word just before the cursor.
632 * returns 0 on success
633 * returns -1 if we could not wrap.
634 */
[fc2677b]635static void _owl_editwin_linewrap_word(owl_editwin *e)
[c9334b1]636{
[fc2677b]637  oe_excursion x;
[84027015]638  gunichar c;
[7d4fbcd]639
[fc2677b]640  oe_save_excursion(e, &x);
[84027015]641
[fc2677b]642  while (owl_editwin_point_move(e, -1)) {
643    c = owl_editwin_get_char_at_point(e);
644    if (owl_util_can_break_after(c) || c == '\n') {
645      if (c != '\n')
646        owl_editwin_replace(e, c != ' ' ? 0 : 1, "\n");
647      break;
[2d4ff14]648    }
[7d4fbcd]649  }
[fc2677b]650
651  oe_restore_excursion(e, &x);
[7d4fbcd]652}
653
[c9334b1]654/* delete the character at the current point, following chars
655 * shift left.
[e20d8179]656 */
[c9334b1]657void owl_editwin_delete_char(owl_editwin *e)
658{
[5b5f3e6]659  owl_editwin_replace(e, 1, "");
[7d4fbcd]660}
661
[c9334b1]662/* Swap the character at point with the character at point-1 and
663 * advance the pointer.  If point is at beginning of buffer do
664 * nothing.  If point is after the last character swap point-1 with
[e20d8179]665 * point-2.  (Behaves as observed in tcsh and emacs).
[c9334b1]666 */
667void owl_editwin_transpose_chars(owl_editwin *e)
668{
[e19eb97]669  const char *middle, *end, *start;
[65b2173]670  char *tmp;
[f2e36b5]671
[47519e1b]672  if (e->bufflen == 0) return;
[e20d8179]673
[5b5f3e6]674  if (e->index == e->bufflen)
675    owl_editwin_point_move(e, -1);     /* point is after last character */
[f2e36b5]676
[5b5f3e6]677  if (owl_editwin_at_beginning_of_buffer(e))
678    return;     /* point is at beginning of buffer, do nothing */
[f2e36b5]679
[47519e1b]680  /* Transpose two utf-8 unicode glyphs. */
[5b5f3e6]681  middle = e->buff + e->index;
[47519e1b]682
[5b5f3e6]683  end = oe_next_point(e, middle);
684  if (end == NULL)
[e20d8179]685    return;
[47519e1b]686
[5b5f3e6]687  start = oe_prev_point(e, middle);
688  if (start == NULL)
[e20d8179]689    return;
[47519e1b]690
[5b5f3e6]691  tmp = owl_malloc((end - start) + 1);
692  tmp[(end - start)] = 0;
693  memcpy(tmp, middle, end - middle);
694  memcpy(tmp + (end - middle), start, middle - start);
695
696  owl_editwin_point_move(e, -1);
697  owl_editwin_replace(e, 2, tmp);
[f2e36b5]698}
699
[c9334b1]700/* insert 'string' at the current point, later text is shifted
701 * right
702 */
[e19eb97]703void owl_editwin_insert_string(owl_editwin *e, const char *s)
[c9334b1]704{
[5b5f3e6]705  owl_editwin_replace(e, 0, s);
[7d4fbcd]706}
707
[a556caa]708/* We assume index is not set to point to a mid-char */
[bab52da]709static gunichar owl_editwin_get_char_at_point(owl_editwin *e)
[c9334b1]710{
[a556caa]711  return g_utf8_get_char(e->buff + e->index);
712}
[7d4fbcd]713
[7f0c26f]714void owl_editwin_exchange_point_and_mark(owl_editwin *e) {
715  int tmp;
716
717  if (e->mark != -1) {
718    tmp = e->mark;
719    owl_editwin_set_mark(e);
720    oe_set_index(e, tmp);
721  }
722}
723
[e20d8179]724int owl_editwin_point_move(owl_editwin *e, int delta)
[84027015]725{
[e19eb97]726  const char *p;
[19f765d]727  int change, d = 0;
[a556caa]728
729  change = MAX(delta, - delta);
730  p = e->buff + e->index;
731
732  while (d < change && p != NULL) {
[e20d8179]733    if (delta > 0)
734      p = oe_next_point(e, p);
735    else
736      p = oe_prev_point(e, p);
737    if (p != NULL) {
[521bc84]738      oe_set_index(e, p - e->buff);
[e20d8179]739      d++;
[a556caa]740    }
741  }
742
743  return delta > 0 ? d : -d;
[84027015]744}
745
[a556caa]746int owl_editwin_at_beginning_of_buffer(owl_editwin *e) {
747  if (e->index == e->lock)
748    return 1;
[84027015]749
[a556caa]750  return 0;
751}
752
753int owl_at_end_of_buffer(owl_editwin *e) {
754  if (e->index == e->bufflen)
755    return 1;
756
757  return 0;
758}
759
[e9c6fc8]760static int owl_editwin_at_beginning_of_line(owl_editwin *e)
[c9334b1]761{
[a0fbdee]762  oe_excursion x;
[a556caa]763  int ret;
[47519e1b]764
[a556caa]765  if (owl_editwin_at_beginning_of_buffer(e))
766    return 1;
[47519e1b]767
[a0fbdee]768  oe_save_excursion(e, &x);
[a556caa]769  owl_editwin_point_move(e, -1);
[bab52da]770  ret = (owl_editwin_get_char_at_point(e) == '\n');
[a0fbdee]771  oe_restore_excursion(e, &x);
[a556caa]772
773  return ret;
774}
775
[e19eb97]776static int owl_editwin_is_char_in(owl_editwin *e, const char *set)
[a556caa]777{
[e19eb97]778  const char *p;
[5b5f3e6]779
780  for (p = set; *p != 0; p = g_utf8_find_next_char(p, NULL))
781    if (owl_editwin_get_char_at_point(e) == g_utf8_get_char(p))
[a556caa]782      return 1;
783  return 0;
784}
785
[e19eb97]786int owl_editwin_move_if_in(owl_editwin *e, int delta, const char *set)
[a556caa]787{
788  int change, distance = 0;
[e20d8179]789  while (owl_editwin_is_char_in(e, set)) {
[a556caa]790    change = owl_editwin_point_move(e, delta);
791    distance += change;
792    if (change == 0)
793      break;
[47519e1b]794  }
[a556caa]795  return distance;
796}
797
[e19eb97]798int owl_editwin_move_if_not_in(owl_editwin *e, int delta, const char *set)
[a556caa]799{
800  int change, distance = 0;
[e20d8179]801  while (!owl_editwin_is_char_in(e, set)) {
[a556caa]802    change = owl_editwin_point_move(e, delta);
803    distance += change;
804    if (change == 0)
805      break;
[7d4fbcd]806  }
[a556caa]807  return distance;
[7d4fbcd]808}
809
[e20d8179]810int owl_editwin_move_to_beginning_of_line(owl_editwin *e)
[47519e1b]811{
[a556caa]812  int distance = 0;
[47519e1b]813
[a556caa]814  if (!owl_editwin_at_beginning_of_line(e)) {
815    /* move off the \n if were at the end of a line */
816    distance += owl_editwin_point_move(e, -1);
817    distance += owl_editwin_move_if_not_in(e, -1, "\n");
818    if (distance && !owl_editwin_at_beginning_of_buffer(e))
819      distance += owl_editwin_point_move(e, 1);
[47519e1b]820  }
[77d4402]821  e->goal_column = 0; /* subtleties */
[84027015]822
[a556caa]823  return distance;
824}
[e20d8179]825
826int owl_editwin_move_to_end_of_line(owl_editwin *e)
[a556caa]827{
828  return owl_editwin_move_if_not_in(e, 1, "\n");
[47519e1b]829}
830
[e20d8179]831int owl_editwin_line_move(owl_editwin *e, int delta)
[c9334b1]832{
[d7043b4]833  int goal_column, change, ll, distance;
834  int count = 0;
[a556caa]835
836  change = MAX(delta, -delta);
837
[d7043b4]838  goal_column = e->goal_column;
839  distance = owl_editwin_move_to_beginning_of_line(e);
840  goal_column = goal_column == -1 ? -distance : goal_column;
[a556caa]841
842  while(count < change) {
843    if (delta > 0) {
844      distance += owl_editwin_move_if_not_in(e, 1, "\n");
845      distance += owl_editwin_point_move(e, 1);
846    } else {
847      /* I really want to assert delta < 0 here */
848      distance += owl_editwin_point_move(e, -1); /* to the newline on
849                                                    the previous line */
850      distance += owl_editwin_move_to_beginning_of_line(e);
851    }
852    count++;
[7d4fbcd]853  }
[a556caa]854
855  distance += (ll = owl_editwin_move_to_end_of_line(e));
856  if (ll > goal_column)
857    distance += owl_editwin_point_move(e, goal_column - ll);
858
859  e->goal_column = goal_column;
860
861  return distance;
[7d4fbcd]862}
863
[c9334b1]864void owl_editwin_backspace(owl_editwin *e)
865{
[7d4fbcd]866  /* delete the char before the current one
867   * and shift later chars left
868   */
[a556caa]869  if(owl_editwin_point_move(e, -1))
[7d4fbcd]870    owl_editwin_delete_char(e);
871}
872
[c9334b1]873void owl_editwin_key_up(owl_editwin *e)
874{
[a556caa]875  owl_editwin_line_move(e, -1);
[7d4fbcd]876}
877
[c9334b1]878void owl_editwin_key_down(owl_editwin *e)
879{
[a556caa]880  owl_editwin_line_move(e, 1);
[7d4fbcd]881}
882
[c9334b1]883void owl_editwin_key_left(owl_editwin *e)
884{
[a556caa]885  owl_editwin_point_move(e, -1);
[7d4fbcd]886}
887
[c9334b1]888void owl_editwin_key_right(owl_editwin *e)
889{
[a556caa]890  owl_editwin_point_move(e, 1);
[7d4fbcd]891}
892
[5b5f3e6]893int owl_editwin_forward_word(owl_editwin *e)
[c9334b1]894{
[5b5f3e6]895  int distance;
[7d4fbcd]896  /* if we're starting on a space, find the first non-space */
[5b5f3e6]897  distance = owl_editwin_move_if_in(e, 1, WHITESPACE);
[7d4fbcd]898
[a556caa]899  /* now find the end of this word */
[5b5f3e6]900  distance += owl_editwin_move_if_not_in(e, 1, WHITESPACE);
901
902  return distance;
903}
904
905void owl_editwin_move_to_nextword(owl_editwin *e)
906{
907  owl_editwin_forward_word(e);
[7d4fbcd]908}
909
[c9334b1]910/* go backwards to the last non-space character
911 */
[5b5f3e6]912int owl_editwin_backward_word(owl_editwin *e)
[c9334b1]913{
[a0fbdee]914  oe_excursion x;
[5b5f3e6]915  int distance = 0;
916  int further = 0;
[a556caa]917  int beginning;
918  /* if in middle of word, beginning of word */
919
920  /* if at beginning of a word, find beginning of previous word */
921
[e20d8179]922  if (owl_editwin_is_char_in(e, WHITESPACE)) {
[a556caa]923    /* if in whitespace past end of word, find a word , the find the beginning*/
[5b5f3e6]924    distance += owl_editwin_move_if_in(e, -1, WHITESPACE); /* leaves us on the last
925                                                              character of the word */
[a0fbdee]926    oe_save_excursion(e, &x);
[a556caa]927    /* are we at the beginning of a word? */
928    owl_editwin_point_move(e, -1);
[e20d8179]929    beginning = owl_editwin_is_char_in(e, WHITESPACE);
[a0fbdee]930    oe_restore_excursion(e, &x);
[a556caa]931    if (beginning)
[5b5f3e6]932      return distance;
[a556caa]933   } else {
934    /* in the middle of the word; */
[a0fbdee]935    oe_save_excursion(e, &x);
[5b5f3e6]936    further += owl_editwin_point_move(e, -1);
[e20d8179]937    if (owl_editwin_is_char_in(e, WHITESPACE)) { /* we were at the beginning */
[5b5f3e6]938      distance += owl_editwin_backward_word(e); /* previous case */
[8321cb7]939      oe_release_excursion(e, &x);
[5b5f3e6]940      return distance + further;
[a556caa]941    } else {
[a0fbdee]942      oe_restore_excursion(e, &x);
[7d4fbcd]943    }
944  }
[5b5f3e6]945  distance += owl_editwin_move_if_not_in(e, -1, WHITESPACE);
[a556caa]946  /* will go past */
947  if (e->index > e->lock)
[5b5f3e6]948    distance += owl_editwin_point_move(e, 1);
949  return distance;
950}
951
952void owl_editwin_move_to_previousword(owl_editwin *e)
953{
954  owl_editwin_backward_word(e);
[7d4fbcd]955}
956
[c9334b1]957void owl_editwin_delete_nextword(owl_editwin *e)
958{
[a0fbdee]959  oe_excursion x;
[a556caa]960
[a0fbdee]961  oe_save_excursion(e, &x);
[a60edf2]962  oe_set_mark(e, e->index);
963  owl_editwin_forward_word(e);
964  owl_editwin_kill_region(e);
965  oe_restore_mark_only(e, &x);
[7d4fbcd]966}
967
[c9334b1]968void owl_editwin_delete_previousword(owl_editwin *e)
969{
[a60edf2]970  oe_excursion x;
[b68f9cd]971
[a60edf2]972  oe_save_excursion(e, &x);
973  oe_set_mark(e, e->index);
974  owl_editwin_backward_word(e);
975  owl_editwin_kill_region(e);
976  oe_restore_mark_only(e, &x);
[b68f9cd]977}
978
[a556caa]979void owl_editwin_move_to_line_end(owl_editwin *e)
[c9334b1]980{
[a556caa]981  owl_editwin_move_to_end_of_line(e);
[7d4fbcd]982}
983
[a556caa]984void owl_editwin_delete_to_endofline(owl_editwin *e)
[c9334b1]985{
[a0fbdee]986  oe_excursion x;
[5b5f3e6]987  int distance;
[a556caa]988
[a0fbdee]989  oe_save_excursion(e, &x);
[a60edf2]990  owl_editwin_set_mark(e);
[5b5f3e6]991  distance = owl_editwin_move_to_end_of_line(e);
[a60edf2]992  if (distance)
993    owl_editwin_kill_region(e);
994  else
995    owl_editwin_replace(e, 1, "");
[a0fbdee]996  oe_restore_excursion(e, &x);
[a60edf2]997}
998
999void owl_editwin_yank(owl_editwin *e)
1000{
1001  if (e->killbuf != NULL)
1002    owl_editwin_replace(e, 0, e->killbuf);
1003}
1004
[e19eb97]1005static const char *oe_copy_buf(owl_editwin *e, const char *buf, int len)
[a60edf2]1006{
1007  char *p;
1008
1009  p = owl_malloc(len + 1);
1010
1011  if (p != NULL) {
1012    owl_free(e->killbuf);
1013    e->killbuf = p;
1014    memcpy(e->killbuf, buf, len);
1015    e->killbuf[len] = 0;
1016  }
1017
1018  return p;
1019}
1020
1021static int oe_copy_region(owl_editwin *e)
1022{
[e19eb97]1023  const char *p;
[a60edf2]1024  int start, end;
1025
1026  if (e->mark == -1)
1027    return 0;
1028
1029  start = MIN(e->index, e->mark);
1030  end = MAX(e->index, e->mark);
1031
1032  p = oe_copy_buf(e, e->buff + start, end - start);
1033  if (p != NULL)
1034    return end - start;
1035  return 0;
1036}
1037
1038void owl_editwin_copy_region_as_kill(owl_editwin *e)
1039{
1040  oe_copy_region(e);
1041}
1042
1043void owl_editwin_kill_region(owl_editwin *e)
1044{
1045  if (e->index > e->mark)
1046    owl_editwin_exchange_point_and_mark(e);
1047
[2184001]1048  owl_editwin_replace_internal(e, oe_copy_region(e), "");
[7d4fbcd]1049}
1050
[c9334b1]1051void owl_editwin_move_to_line_start(owl_editwin *e)
1052{
[a556caa]1053  owl_editwin_move_to_beginning_of_line(e);
[7d4fbcd]1054}
1055
[c9334b1]1056void owl_editwin_move_to_end(owl_editwin *e)
1057{
[521bc84]1058  oe_set_index(e, e->bufflen);
[7d4fbcd]1059}
1060
[c9334b1]1061void owl_editwin_move_to_top(owl_editwin *e)
1062{
[521bc84]1063  oe_set_index(e, e->lock);
[7d4fbcd]1064}
1065
[2fc8397]1066void owl_editwin_backward_paragraph(owl_editwin *e)
1067{
1068  owl_editwin_point_move(e, -1);
1069  for (; e->index >= e->lock; owl_editwin_point_move(e, -1)) {
1070    if (e->index <= e->lock ||
1071        ((e->buff[e->index] == '\n') && (e->buff[e->index - 1]=='\n')))
1072      break;
1073  }
1074}
1075
1076void owl_editwin_forward_paragraph(owl_editwin *e)
1077{
1078  owl_editwin_point_move(e, 1);
1079  /* scan forward to the start of the next paragraph */
1080  for(; e->index < e->bufflen; owl_editwin_point_move(e, 1)) {
1081    if (e->buff[e->index -1] == '\n' && e->buff[e->index] == '\n')
1082      break;
1083  }
1084}
1085
[d41294a]1086int owl_editwin_current_column(owl_editwin *e)
[c9334b1]1087{
[a0fbdee]1088  oe_excursion x;
[fc2677b]1089  int lineindex;
[7d4fbcd]1090
[a0fbdee]1091  oe_save_excursion(e, &x);
[fc2677b]1092  owl_editwin_move_to_beginning_of_line(e);
1093  lineindex = e->index;
1094  oe_restore_excursion(e, &x);
1095  return oe_region_width(e, lineindex, e->index, 0);
1096}
[a556caa]1097
[fc2677b]1098void owl_editwin_fill_paragraph(owl_editwin *e)
1099{
1100  oe_excursion x;
1101  gunichar ch;
1102  int sentence;
[7d4fbcd]1103
[d625cfd]1104  if (e->fillcol < 0)
1105    /* auto-fill disabled */
1106    return;
1107
[fc2677b]1108  oe_save_excursion(e, &x);
[7d4fbcd]1109
[fc2677b]1110  /* Mark the end of the paragraph */
1111  owl_editwin_forward_paragraph(e);
1112  /* Skip the trailing newline */
1113  owl_editwin_point_move(e, -1);
1114  owl_editwin_set_mark(e);
[7d4fbcd]1115
[fc2677b]1116  owl_editwin_backward_paragraph(e);
[7d4fbcd]1117
[fc2677b]1118  /* Don't mess with the leading newline */
1119  if (owl_editwin_get_char_at_point(e) == '\n')
1120    owl_editwin_point_move(e, 1);
[7d4fbcd]1121
[fc2677b]1122  /*
1123   * First pass: Scan forward replacing all series of spaces with ' '
1124   * (or nothing after CJK ideograms)
1125   */
1126  sentence = 0;
1127  for(;e->index < e->mark; owl_editwin_point_move(e, 1)) {
[50e671c]1128    /* bail if we hit a trailing dot on the buffer */
[fc2677b]1129    if (strcmp(e->buff + e->index, "\n.") == 0) {
1130      owl_editwin_set_mark(e);
[50e671c]1131      break;
[7d4fbcd]1132    }
1133
[fc2677b]1134    ch = owl_editwin_get_char_at_point(e);
[b2c1bd4]1135
[fc2677b]1136    if (owl_util_can_break_after(ch) || ch == '\n') {
1137      if (g_unichar_isspace(ch)) {
1138        owl_editwin_replace(e, 1, " ");
1139      }
1140
[f9d257b]1141      if (sentence && g_unichar_isspace(owl_editwin_get_char_at_point(e))
1142          && e->index < e->mark)
[fc2677b]1143        owl_editwin_point_move(e, 1);
1144
1145      while(g_unichar_isspace(owl_editwin_get_char_at_point(e))
1146            && e->index < e->mark) {
1147        owl_editwin_delete_char(e);
[7d4fbcd]1148      }
1149    }
[fc2677b]1150
1151    if(ch == '.' || ch == '!' || ch == '?')
1152      sentence = 1;
1153    else
1154      sentence = 0;
1155  }
1156
1157  owl_editwin_backward_paragraph(e);
1158
1159  /* Now go through inserting newlines as needed */
1160  while(e->index < e->mark) {
1161    /* if we've travelled too far, linewrap */
[d41294a]1162    if (owl_editwin_current_column(e) >= e->fillcol)
[fc2677b]1163      _owl_editwin_linewrap_word(e);
1164    owl_editwin_point_move(e, 1);
[7d4fbcd]1165  }
1166
[a0fbdee]1167  oe_restore_excursion(e, &x);
[7d4fbcd]1168}
1169
[cf83b7a]1170/* returns true if only whitespace remains */
[c9334b1]1171int owl_editwin_is_at_end(owl_editwin *e)
1172{
[a556caa]1173  return (only_whitespace(e->buff + e->index));
[217a43e]1174}
1175
[bab52da]1176static int owl_editwin_check_dotsend(owl_editwin *e)
[c9334b1]1177{
[dc7884d]1178  int zdot = 0;
[72ab15f]1179  oe_excursion x;
[7d4fbcd]1180
1181  if (!e->dotsend) return(0);
[4ccd92c]1182  if (!owl_editwin_is_at_end(e)) return (0);
[47519e1b]1183
[72ab15f]1184  oe_save_excursion(e, &x);
1185
1186  owl_editwin_point_move(e, -3);
1187
[4ccd92c]1188  if(strncmp(e->buff + e->index, "\n.\n", 3) == 0) {
[dc7884d]1189    owl_editwin_point_move(e, 1);
1190    zdot = 1;
[0509efc]1191  } else if(e->index == e->lock &&
[4ccd92c]1192            strncmp(e->buff + e->index, ".\n", 2) == 0) {
[0509efc]1193    zdot = 1;
1194  }
1195
1196  if(zdot) {
[4ccd92c]1197    owl_editwin_set_mark(e);
1198    owl_editwin_move_to_end(e);
1199    owl_editwin_replace_region(e, "");
[dc7884d]1200  }
[72ab15f]1201
1202  oe_restore_excursion(e, &x);
1203
1204  return zdot;
[7d4fbcd]1205}
1206
[fac5463]1207void owl_editwin_post_process_char(owl_editwin *e, owl_input j)
[c9334b1]1208{
[a556caa]1209  /* XXX force a redisplay? */
[fac5463]1210  if ((j.ch==13 || j.ch==10) && owl_editwin_check_dotsend(e)) {
[435d6b2]1211    owl_command_edit_done(e);
[7d4fbcd]1212    return;
1213  }
[2ee9e8d]1214  owl_editwin_redisplay(e);
[7d4fbcd]1215}
1216
[3e36085]1217static int oe_region_width(owl_editwin *e, int start, int end, int offset)
[16cfd12a]1218{
[e19eb97]1219  const char *p;
[3e36085]1220  int width = offset;
1221 
[16cfd12a]1222  for(p = e->buff + start;
1223      p < e->buff + end;
1224      p = g_utf8_find_next_char(p, NULL))
1225    width += oe_char_width(g_utf8_get_char(p), width);
1226
[3e36085]1227  return width - offset;
[16cfd12a]1228}
1229
[ebf0128]1230static void oe_insert_char(owl_editwin *e, gunichar c)
[fac5463]1231{
[16cfd12a]1232  oe_excursion x;
[5b5f3e6]1233  char tmp[7];
[16cfd12a]1234  int replaced = -1;
[5b5f3e6]1235
[ebf0128]1236  if (c == '\r') /* translate CRs to NLs */
1237    c = '\n';
1238
[16cfd12a]1239  if (!g_unichar_iscntrl(c) || c == '\n' || c== '\t' ) {
[ebf0128]1240    if (c == '\n' && e->style == OWL_EDITWIN_STYLE_ONELINE) {
1241      return;
1242    }
1243
[d625cfd]1244    if (e->wrapcol > 0 && e->cursorx != -1 &&
1245        e->cursorx + oe_char_width(c, e->cursorx) > e->wrapcol) {
[16cfd12a]1246      /* XXX this is actually wrong:
1247       * + If the line has been been wrapped, we can be past the wrap column but
1248       *   e->cursorx be much smaller.
1249       * + If the user went back and inserted a bunch of stuff in the middle of
1250       *   the line, there may be more than one word past the wrap column.
1251       */
1252      oe_save_excursion(e, &x);
1253
1254      if (c == ' ' || c == '\t') {
1255        owl_editwin_point_move(e, -1);
1256        replaced = -owl_editwin_move_if_in(e, -1, " \t");
1257        if (!replaced) {
1258          c = '\n';
1259          replaced = -1;
1260        }
1261      } else {
1262        while(!owl_editwin_at_beginning_of_line(e)) {
1263          owl_editwin_point_move(e, -1);
1264          if (owl_util_can_break_after(owl_editwin_get_char_at_point(e))) {
1265            replaced = -owl_editwin_move_if_in(e, -1, " \t");
1266            break;
1267          }
1268        }
1269        if (owl_editwin_at_beginning_of_line(e))
1270          replaced = -1;
1271      }
1272      if (replaced && !owl_editwin_at_beginning_of_line(e))
1273        owl_editwin_point_move(e, 1);
1274      if (replaced >= 0) {
1275        owl_editwin_replace(e, replaced, "\n");
1276      }
1277      oe_restore_excursion(e, &x);
1278    }
1279
1280    if (replaced >= 0 && (c == ' ' || c == '\t'))
1281      return; /* our work here is done */
1282
[6c171f1]1283    tmp[g_unichar_to_utf8(c, tmp)] = '\0';
[ebf0128]1284    owl_editwin_replace(e, 0, tmp);
1285  }
1286}
1287
1288void owl_editwin_process_char(owl_editwin *e, owl_input j)
1289{
[5b5f3e6]1290  if (j.ch == ERR)
1291    return;
[fac5463]1292  /* Ignore ncurses control characters. */
[e20d8179]1293  if (j.ch < 0x100) {
[ebf0128]1294    oe_insert_char(e, j.uch);
[fac5463]1295  }
1296}
1297
[e19eb97]1298const char *owl_editwin_get_text(owl_editwin *e)
[c9334b1]1299{
[7d4fbcd]1300  return(e->buff+e->lock);
1301}
1302
[d41294a]1303char *owl_editwin_get_region(owl_editwin *e)
1304{
1305  int start, end;
1306  start = e->index;
1307  end   = e->mark;
1308  if(start > end) {
1309    int tmp = end;
1310    end = start;
1311    start = tmp;
1312  }
1313
1314  return oe_chunk(e, start, end);
1315}
1316
[77f605d]1317int owl_editwin_get_echochar(owl_editwin *e)
1318{
[a556caa]1319  return e->echochar;
1320}
[77f605d]1321
1322static char *oe_chunk(owl_editwin *e, int start, int end)
1323{
1324  char *p;
1325 
1326  p = owl_malloc(end - start + 1);
1327  memcpy(p, e->buff + start, end - start);
1328  p[end - start] = 0;
1329
1330  return p;
1331}
1332
[d41294a]1333/*
1334 * The only guarantee made about these values is that comparisons
1335 * between them, as well as comparison between multiple calls to these
1336 * functions without modifying the editwin in-between, are meaningful.
1337 */
1338
1339int owl_editwin_get_point(owl_editwin *e)
1340{
1341  return e->index;
1342}
1343
1344int owl_editwin_get_mark(owl_editwin *e)
1345{
1346  return e->mark;
1347}
1348
[2f21a41]1349
1350/*
1351 * Local Variables:
1352 * mode:C
1353 * c-basic-offset:2
1354 * End:
1355 */
Note: See TracBrowser for help on using the repository browser.