source: editwin.c @ 5b5f3e6

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