source: editwin.c @ 83a079a

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