Logo Search packages:      
Sourcecode: joe version File versions  Download package

uformat.c

/*
 *    User text formatting functions
 *    Copyright
 *          (C) 1992 Joseph H. Allen
 *
 *    This file is part of JOE (Joe's Own Editor)
 */
#include "types.h"

/* Center line cursor is on and move cursor to beginning of next line */

int ucenter(BW *bw)
{
      P *p = bw->cursor, *q;
      long endcol, begcol, x;
      int c;

      p_goto_eol(p);
      while (joe_isblank(bw->b->o.charmap, (c = prgetc(p))))
            /* do nothing */;
      if (c == '\n') {
            pgetc(p);
            goto done;
      }
      if (c == NO_MORE_DATA)
            goto done;
      pgetc(p);
      endcol = piscol(p);

      p_goto_bol(p);
      while (joe_isblank(bw->b->o.charmap, (c = pgetc(p))))
            /* do nothing */;
      if (c == '\n') {
            prgetc(p);
            goto done;
      }
      if (c == NO_MORE_DATA)
            goto done;
      prgetc(p);
      begcol = piscol(p);

      if (endcol - begcol > bw->o.rmargin + bw->o.lmargin)
            goto done;

      q = pdup(p, USTR "ucenter");
      p_goto_bol(q);
      bdel(q, p);
      prm(q);

      for (x = 0; x != (bw->o.lmargin + bw->o.rmargin) / 2 - (endcol - begcol) / 2; ++x)
            binsc(p, ' ');

      done:
      if (!pnextl(p)) {
            binsc(p, '\n');
            pgetc(p);
            return -1;
      } else
            return 0;
}

/* Return true if c is a character which can indent a paragraph */

/*   > is for mail/news
 *   * is for C comments
 *   / is for C++ comments
 *   # is for shell script comments
 *   % is for TeX comments
 */

static int cpara(BW *bw, int c)
{
      int x;
      if (c == ' ' || c == '\t')
            return 1;
      if (bw->o.cpara)
            for (x = 0; bw->o.cpara[x]; ++x)
                  if (bw->o.cpara[x] == c)
                        return 1;
      return 0;
#ifdef junk
      if (c == ' ' || c == '\t' || c == '\\' ||
          c == '>' || c == '|' || c == ':' || c == '*' || c == '/' ||
          c == ',' || c == '.' || c == '?' || c == ';' || c == ']' ||
          c == '}' || c == '=' || c == '+' || c == '-' || c == '_' ||
          c == ')' || c == '&' || c == '^' || c == '%' || c == '$' ||
          c == '#' || c == '@' || c == '!' || c == '~')
            return 1;
      else
            return 0;
#endif
}

/* Return true if line is definitly not a paragraph line.
 * Lines which arn't paragraph lines:
 *  1) Blank lines
 *  2) Lines which begin with '.'
 */

static int pisnpara(BW *bw, P *p)
{
      P *q;
      int c;

      q = pdup(p, USTR "pisnpara");
      p_goto_bol(q);
      while (cpara(bw, c = pgetc(q)))
            /* do nothing */;
      prm(q);
      if (c == '.' || c == '\r' || c == '\n')
            return 1;
      else
            return 0;
}

/* Determine amount of indentation on current line.  Set first
   to include '-' and '*' bullets. */

static long nindent(BW *bw, P *p, int first)
{
      P *q = pdup(p, USTR "nindent");
      long col;
      int c;

      p_goto_bol(q);
      do {
            col = q->col;
      } while (cpara(bw, (c = pgetc(q))));
      if (first && (c == '-' || c == '*')) {
            c = pgetc(q);
            if (c == ' ') {
                  col = q->col;
            }
      }
      prm(q);
      return col;
}

/* Get indentation prefix column */

static long prefix(BW *bw, P *p,int up)
{
      long len;
      P *q = pdup(p, USTR "prefix");

      p_goto_bol(q);
      while (cpara(bw, brch(q)))
            pgetc(q);
      while (!pisbol(q)) {
            /* int c; */
            if (!joe_isblank(p->b->o.charmap, ( /* c = */ prgetc(q)))) {
            /*
                  if (up && (c == '*' || c == '-')) {
                        if (!pisbol(q)) {
                              c = prgetc(q);
                              pgetc(q);
                              if (c == ' ' || c == '\t')
                                    goto skip;
                        } else
                              goto skip;
                  }
                  pgetc(q);
            */
                  break;
            /*    skip:; */
            }
      }
      len = piscol(q);
      prm(q);
      return len;
}

/* Move pointer to beginning of paragraph
 *
 * This function simply moves backwards until it sees:
 *  0) The beginning of the file
 *  1) A blank line
 *  2) A line with a different indentation prefix
 *  3) A line with indentation greater than that of the line we started with
 *  4) A line with indentation less than that of the starting line, but with
 *     a blank line (or beginning of file) preceeding it.
 */

int within = 0;

P *pbop(BW *bw, P *p)
{
      long indent;
      long prelen;

      p_goto_bol(p);
      indent = nindent(bw, p, 0);
      prelen = prefix(bw, p, 0);
      while (!pisbof(p) && (!within || !markb || p->byte > markb->byte)) {
            long ind;
            long len;

            pprevl(p);
            p_goto_bol(p);
            ind = nindent(bw, p, 0);
            len = prefix(bw, p, 0);
            if (pisnpara(bw, p) || len != prelen) {
                  pnextl(p);
                  break;
            }
            if (ind > indent) {
                  int ok = 1;
                  P *q = pdup(p, USTR "pbop");
                  if (pprevl(q)) {
                        p_goto_bol(q);
                        if (nindent(bw, q, 0) == ind)
                              ok = 0;
                  }
                  prm(q);
                  if (!ok)
                        pnextl(p);
                  break;
            }
            if (ind < indent) {
                  break;
                  /* if (pisbof(p)) {
                        break;
                  }
                  pprevl(p);
                  p_goto_bol(p);
                  if (pisnpara(bw, p)) {
                        pnextl(p);
                        break;
                  } else {
                        pnextl(p);
                        pnextl(p);
                        break;
                  } */
            }
      }
      return p;
}

/* Move pointer to end of paragraph.  Pointer must already be on first
 * line of paragraph for this to work correctly.
 *
 * This function moves forwards until it sees:
 *  0) The end of the file.
 *  1) A blank line
 *  2) A line with indentation different from the second line of the paragraph
 *  3) A line with prefix column different from first line
 */

P *peop(BW *bw, P *p)
{
      long indent;
      long prelen;

      if (!pnextl(p) || pisnpara(bw, p) || (within && markk && p->byte >= markk->byte))
            return p;
      indent = nindent(bw, p, 0);
      prelen = prefix(bw, p, 0);
      while (pnextl(p) && (!within || !markk || p->byte < markk->byte)) {
            long ind = nindent(bw, p, 0);
            long len = prefix(bw, p, 0);

            if (ind != indent || len != prelen || pisnpara(bw, p))
                  break;
      }
      return p;
}

/* Motion commands */

int ubop(BW *bw)
{
      P *q = pdup(bw->cursor, USTR "ubop");

      up:
      while (pisnpara(bw, q) && !pisbof(q) && (!within || !markb || q->byte > markb->byte))
            pprevl(q);
      pbop(bw, q);
      if (q->byte != bw->cursor->byte) {
            pset(bw->cursor, q);
            prm(q);
            return 0;
      } else if (!pisbof(q)) {
            prgetc(q);
            goto up;
      } else {
            prm(q);
            return -1;
      }
}

int ueop(BW *bw)
{
      P *q = pdup(bw->cursor, USTR "ueop");

      up:
      while (pisnpara(bw, q) && !piseof(q))
            pnextl(q);
      pbop(bw, q);
      peop(bw, q);
      if (q->byte != bw->cursor->byte) {
            pset(bw->cursor, q);
            prm(q);
            return 0;
      } else if (!piseof(q)) {
            pnextl(q);
            goto up;
      } else {
            prm(q);
            return -1;
      }
}

/* Wrap word.  If 'french' is set, only one space will be placed
 * after . ? or !
 */

void wrapword(BW *bw, P *p, long int indent, int french, unsigned char *indents)
{
      P *q;
      P *r;
      P *s;
      int rmf = 0;
      int c;
      long to = p->byte;
      int my_indents = 0;
      
      /* autoindent when called by utype */
      if (!indents) {
            /* Get indentation prefix from beginning of line */
            s = pdup(p, USTR "wrapword");
            p_goto_bol(s);
            pbop(bw, s);
            /* Record indentation of second line of paragraph, of first
             * line if there is only one line */
            q = pdup(s, USTR "wrapword");
            pnextl(q);
            if (q->line < p->line) {
                  /* Second line */
                  P *r = pdup(q, USTR "wrapword");

                  indent = nindent(bw, q, 0);
                  pcol(r, indent);
                  indents = brs(q, r->byte - q->byte);
                  prm(r);
            } else {
                  /* First line */
                  P *r = pdup(s, USTR "uformat");
                  int x;

                  indent = nindent(bw, s, 1);
                  pcol(r, indent);
                  indents = brs(s, r->byte - s->byte);
                  prm(r);
                  /* Ignore blanks unless autoindent is on */
                  for (x = 0; indents[x] == ' ' || indents[x] == '\t'; ++x);
                  if (!indents[x] && !bw->o.autoindent) {
                        indents[0] = 0;
                        x = 0;
                  }
                  /* Don't duplicate bullet, but leave VHDL comment */
                  while (indents[x])
                        ++x;
                  if (x >= 2 && indents[x - 1] == ' ' &&
                      ((indents[x - 2] == '*' && (x == 2 || indents[x - 3] == ' ' || indents[x - 3] == '\t')) || (indents[x - 2] == '-' && (x == 2 || indents[x - 3] != '-')))) {
                        indents[x - 2] = ' ';
                  }
                  /* Fix C comment */
                  if (x >= 3 && indents[x - 3] == '/' && indents[x - 2] == '*' && indents[x - 1] == ' ')
                        indents[x - 3] = ' ';
                  
            }
            my_indents = 1;
            prm(q);
            prm(s);
      }


/*
      if(!indents) {
            int f = 0;
            P *r = pdup(p);

            p_goto_bol(r);
            q = pdup(r);
            while(cpara(c = brc(q))) {
                  if(!joe_isblank(c))
                        f = 1;
                  pgetc(q);
            }
            if(f) {
                  indents = brs(r, q->byte-r->byte);
                  rmf = 1;
                  if(indents[0] == '/' && indents[1] == '*')
                        indents[0] = ' ';
            }
            prm(r);
            prm(q);
      }
*/

      /* Get to beginning of word */
      while (!pisbol(p) && piscol(p) > indent && !joe_isblank(p->b->o.charmap, prgetc(p)))
            /* do nothing */;

      /* If we found the beginning of a word... */
      if (!pisbol(p) && piscol(p) > indent) {
            /* Move q to two (or one if 'french' is set) spaces after end of previous
               word */
            q = pdup(p, USTR "wrapword");
            while (!pisbol(q))
                  if (!joe_isblank(p->b->o.charmap, (c = prgetc(q)))) {
                        pgetc(q);
                        if ((c == '.' || c == '?' || c == '!')
                            && q->byte != p->byte && !french)
                              pgetc(q);
                        break;
                  }
            pgetc(p);

            /* Delete space between start of word and end of previous word */
            to -= p->byte - q->byte;
            bdel(q, p);
            prm(q);

            /* Move word to beginning of next line */
            binsc(p, '\n');
            
            /* Take care that wordwrap is done the right way when overtype mode is active */
            if (p->b->o.overtype){
                  /* delete the next line break which is unnecessary */
                  r = pdup(p, USTR "wrapword");
                  /* p_goto_eol(r); */
                  pgetc(r);
                  p_goto_eol(r);
                  s = pdup(r, USTR "wrapword");
                  pgetc(r);
                  bdel(s,r);
                  binsc(r, ' ');
                  
                  /* Now we got to take care that all subsequent lines are not longer than the right margin */
                  /* Move cursor to right margin */
                  pfwrd(r, r->b->o.rmargin - r->col);
                  
                  /* Make a copy of the cursor and move the copied cursor to the end of the line */
                  prm(s);
                  s = pdup(r, USTR "wrapword");
                  p_goto_eol(s);
                  
                  /* If s is located behind r then the line goes beyond the right margin and we need to call wordwrap() for that line. */
                  if (r->byte < s->byte){
                        wrapword(bw, r, indent, french, indents);
                  }
                  
                  prm(r);
                  prm(s);
            }
            
            ++to;
            if (p->b->o.crlf)
                  ++to;
            pgetc(p);

            /* Indent to left margin */
            if (indents) {
                  binss(p, indents);
                  to += zlen(indents);
            } else
                  while (indent--) {
                        binsc(p, ' ');
                        ++to;
                  }

            if (rmf)
                  joe_free(indents);
      }

      /* Move cursor back to original position */
      pfwrd(p, to - p->byte);
      if (my_indents)
            joe_free(indents);
}

/* Reformat paragraph */

int uformat(BW *bw)
{
      long indent;
      unsigned char *indents;
      B *buf;
      P *b;
      long curoff;
      int c;
      P *p, *q;

      p = pdup(bw->cursor, USTR "uformat");
      p_goto_bol(p);

      /* Do nothing if we're not on a paragraph line */
      if (pisnpara(bw, p)) {
            prm(p);
            return 0;
      }

      /* Move p to beginning of paragraph, bw->cursor to end of paragraph and
       * set curoff to original cursor offset within the paragraph */
      pbop(bw, p);
      curoff = bw->cursor->byte - p->byte;
      pset(bw->cursor, p);
      peop(bw, bw->cursor);

      /* Ensure that paragraph ends on a beginning of a line */
      if (!pisbol(bw->cursor))
            binsc(bw->cursor, '\n'), pgetc(bw->cursor);

      /* Record indentation of second line of paragraph, of first line if there
       * is only one line */
      q = pdup(p, USTR "uformat");
      pnextl(q);
      if (q->line != bw->cursor->line) {
            P *r = pdup(q, USTR "uformat");

            indent = nindent(bw, q, 0);
            pcol(r, indent);
            indents = brs(q, r->byte - q->byte);
            prm(r);
      } else {
            P *r = pdup(p, USTR "uformat");

            indent = nindent(bw, p, 0);
            pcol(r, indent);
            indents = brs(p, r->byte - p->byte);
            prm(r);
      }
      prm(q);

      /* Fix C */
      if (indents[0] == '/' && indents[1] == '*' && indents[2] == ' ')
            indents[0] = ' ';

      /* But if the left margin is greater, we use that instead */
      if (bw->o.lmargin > indent)
            indent = bw->o.lmargin;

      /* Cut paragraph into new buffer */
      
      /* New buffer needs to inherit UTF-8 and CR-LF options */
      buf = bcpy(p, bw->cursor);
      buf->o.crlf = p->b->o.crlf;
      buf->o.charmap = p->b->o.charmap;
      bdel(p, bw->cursor);

      /* text is in buffer.  insert it at cursor */

      /* Do first line */
      b = pdup(buf->bof, USTR "uformat");

      while (!piseof(b)) {
            /* Set cursor position if we're at original offset */
            if (b->byte == curoff)
                  pset(bw->cursor, p);

            /* Get character from buffer */
            c = pgetc(b);

            /* Stop if we found end of line */
            if (c == '\n') {
                  prgetc(b);
                  break;
            }

            /* Stop if we found white-space followed by end of line */
            if (joe_isblank(b->b->o.charmap, c) && piseolblank(b))
                  break;

            /* Insert character, advance pointer */
            binsc(p, c);
            pgetc(p);

            /* Do word wrap if we reach right margin */
            if (piscol(p) > bw->o.rmargin && !joe_isblank(p->b->o.charmap,c)) {
                  wrapword(bw, p, indent, bw->o.french, indents);
                  break;
            }
      }

      /* Do rest */

      while (!piseof(b)) {
            c = brch(b);
            if (joe_isblank(b->b->o.charmap,c) || c == '\n') {
                  int f = 0;
                  P *d;
                  int g;

                  /* Set f if there are two spaces after . ? or ! instead of one */
                  /* (What is c was '\n'?) */
                  d=pdup(b, USTR "uformat");
                  g=prgetc(d);
                  if (g=='.' || g=='?' || g=='!') {
                        pset(d,b);
                        pgetc(d);
                        if (joe_isspace(bw->b->o.charmap,brch(d)))
                              f = 1;
                  }
                  prm(d);
                  
                  /* Skip past the whitespace.  Skip over indentations */
                  loop:
                  
                  c = brch(b);
                  if (c == '\n') {
                        if (b->byte == curoff)
                              pset(bw->cursor, p);

                        pgetc(b);
                        while (cpara(bw, (c=brch(b)))) {
                              if (b->byte == curoff)
                                    pset(bw->cursor, p);
                              pgetc(b);
                        }
                  }

                  if (joe_isblank(b->b->o.charmap,c)) {
                        if(b->byte == curoff)
                              pset(bw->cursor, p);
                        pgetc(b);
                        goto loop;
                  }

                  /* Insert proper amount of whitespace */
                  if (!piseof(b)) {
                        if (f && !bw->o.french)
                              binsc(p, ' '), pgetc(p);
                        binsc(p, ' ');
                        pgetc(p);
                  }
            } else {
                  /* Insert characters of word and wrap if necessary */
                  if (b->byte == curoff)
                        pset(bw->cursor, p);

                  binsc(p, pgetc(b));
                  pgetc(p);
                  if (piscol(p) > bw->o.rmargin)
                        wrapword(bw, p, indent, bw->o.french, indents);
            }
      }

      binsc(p, '\n');
      prm(p);
      brm(buf);
      joe_free(indents);
      return 0;
}

/* Format entire block */

int ufmtblk(BW *bw)
{
      if (markv(1) && bw->cursor->byte >= markb->byte && bw->cursor->byte <= markk->byte) {
            markk->end = 1;
            utomarkk(bw);
            within = 1;
            do {
                  ubop(bw), uformat(bw);
            } while (bw->cursor->byte > markb->byte);
            within = 0;
            markk->end = 0;
            if (lightoff)
                  unmark(bw);
            return 0;
      } else
            return uformat(bw);
}

Generated by  Doxygen 1.6.0   Back to index