123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- /* wordproc.c - word-processor mode for the editor: does dynamic
- paragraph formatting.
- Copyright (C) 1996 Paul Sheer
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
- */
- #include <config.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <sys/types.h>
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <stdlib.h>
- #include "../src/global.h"
- #include "edit.h"
- #include "edit-widget.h"
- #define tab_width option_tab_spacing
- #ifndef UTF8
- #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
- #else /* UTF8 */
- #define NO_FORMAT_CHARS_START L"-+*\\,.;:&>"
- #endif /* UTF8 */
- #define FONT_MEAN_WIDTH 1
- static long
- line_start (WEdit *edit, long line)
- {
- long p, l;
- l = edit->curs_line;
- p = edit->curs1;
- if (line < l)
- p = edit_move_backward (edit, p, l - line);
- else if (line > l)
- p = edit_move_forward (edit, p, line - l, 0);
- p = edit_bol (edit, p);
- #ifndef UTF8
- while (strchr ("\t ", edit_get_byte (edit, p)))
- #else /* UTF8 */
- while (wcschr (L"\t ", edit_get_byte (edit, p)))
- #endif /* UTF8 */
- p++;
- return p;
- }
- static int bad_line_start (WEdit * edit, long p)
- {
- mc_wint_t c;
- c = edit_get_byte (edit, p);
- if (c == '.') { /* `...' is acceptable */
- if (edit_get_byte (edit, p + 1) == '.')
- if (edit_get_byte (edit, p + 2) == '.')
- return 0;
- return 1;
- }
- if (c == '-') {
- if (edit_get_byte (edit, p + 1) == '-')
- if (edit_get_byte (edit, p + 2) == '-')
- return 0; /* `---' is acceptable */
- return 1;
- }
- #ifndef UTF8
- if (strchr (NO_FORMAT_CHARS_START, c))
- #else /* UTF8 */
- if (wcschr (NO_FORMAT_CHARS_START, c))
- #endif /* UTF8 */
- return 1;
- return 0;
- }
- /*
- * Find the start of the current paragraph for the purpose of formatting.
- * Return position in the file.
- */
- static long
- begin_paragraph (WEdit *edit, int force)
- {
- int i;
- for (i = edit->curs_line - 1; i >= 0; i--) {
- if (line_is_blank (edit, i)) {
- i++;
- break;
- }
- if (force) {
- if (bad_line_start (edit, line_start (edit, i))) {
- i++;
- break;
- }
- }
- }
- return edit_move_backward (edit, edit_bol (edit, edit->curs1),
- edit->curs_line - i);
- }
- /*
- * Find the end of the current paragraph for the purpose of formatting.
- * Return position in the file.
- */
- static long
- end_paragraph (WEdit *edit, int force)
- {
- int i;
- for (i = edit->curs_line + 1; i <= edit->total_lines; i++) {
- if (line_is_blank (edit, i)) {
- i--;
- break;
- }
- if (force)
- if (bad_line_start (edit, line_start (edit, i))) {
- i--;
- break;
- }
- }
- return edit_eol (edit,
- edit_move_forward (edit, edit_bol (edit, edit->curs1),
- i - edit->curs_line, 0));
- }
- static mc_wchar_t *
- get_paragraph (WEdit *edit, long p, long q, int indent, int *size)
- {
- mc_wchar_t *s, *t;
- #if 0
- t = g_malloc (((q - p) + 2 * (q - p) / option_word_wrap_line_length +
- 10) * sizeof(mc_wchar_t));
- #else
- t = g_malloc ((2 * (q - p) + 100) * sizeof(mc_wchar_t));
- #endif
- if (!t)
- return 0;
- for (s = t; p < q; p++, s++) {
- if (indent)
- if (edit_get_byte (edit, p - 1) == '\n')
- #ifndef UTF8
- while (strchr ("\t ", edit_get_byte (edit, p)))
- #else /* UTF8 */
- while (wcschr (L"\t ", edit_get_byte (edit, p)))
- #endif /* UTF8 */
- p++;
- *s = edit_get_byte (edit, p);
- }
- *size = s - t;
- t[*size] = '\n';
- return t;
- }
- static void strip_newlines (mc_wchar_t *t, int size)
- {
- mc_wchar_t *p = t;
- while (size--) {
- *p = *p == '\n' ? ' ' : *p;
- p++;
- }
- }
- /*
- This is a copy of the function
- int calc_text_pos (WEdit * edit, long b, long *q, int l)
- in propfont.c :(
- It calculates the number of chars in a line specified to length l in pixels
- */
- static inline int next_tab_pos (int x)
- {
- return x += tab_width - x % tab_width;
- }
- static int line_pixel_length (mc_wchar_t *t, long b, int l)
- {
- int x = 0, c, xn = 0;
- for (;;) {
- c = t[b];
- switch (c) {
- case '\n':
- return b;
- case '\t':
- xn = next_tab_pos (x);
- break;
- default:
- xn = x + 1;
- break;
- }
- if (xn > l)
- break;
- x = xn;
- b++;
- }
- return b;
- }
- static int
- next_word_start (mc_wchar_t *t, int q, int size)
- {
- int i;
- int saw_ws = 0;
- for (i = q; i < size; i++) {
- switch (t[i]) {
- case '\n':
- return -1;
- case '\t':
- case ' ':
- saw_ws = 1;
- break;
- default:
- if (saw_ws != 0)
- return i;
- break;
- }
- }
- return -1;
- }
- /* find the start of a word */
- static int
- word_start (mc_wchar_t *t, int q, int size)
- {
- int i = q;
- if (t[q] == ' ' || t[q] == '\t')
- return next_word_start (t, q, size);
- for (;;) {
- int c;
- if (!i)
- return -1;
- c = t[i - 1];
- if (c == '\n')
- return -1;
- if (c == ' ' || c == '\t')
- return i;
- i--;
- }
- }
- /* replaces ' ' with '\n' to properly format a paragraph */
- static void format_this (mc_wchar_t *t, int size, int indent)
- {
- int q = 0, ww;
- strip_newlines (t, size);
- ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
- if (ww < FONT_MEAN_WIDTH * 2)
- ww = FONT_MEAN_WIDTH * 2;
- for (;;) {
- int p;
- q = line_pixel_length (t, q, ww);
- if (q > size)
- break;
- if (t[q] == '\n')
- break;
- p = word_start (t, q, size);
- if (p == -1)
- q = next_word_start (t, q, size); /* Return the end of the word if the beginning
- of the word is at the beginning of a line
- (i.e. a very long word) */
- else
- q = p;
- if (q == -1) /* end of paragraph */
- break;
- if (q)
- t[q - 1] = '\n';
- }
- }
- static void replace_at (WEdit * edit, long q, mc_wint_t c)
- {
- edit_cursor_move (edit, q - edit->curs1);
- edit_delete (edit);
- edit_insert_ahead (edit, c);
- }
- /* replaces a block of text */
- static void
- put_paragraph (WEdit * edit, mc_wchar_t *t, long p, int indent, int size)
- {
- long cursor;
- int i;
- mc_wchar_t c = 0;
- cursor = edit->curs1;
- if (indent)
- #ifndef UTF8
- while (strchr ("\t ", edit_get_byte (edit, p)))
- #else /* UTF8 */
- while (wcschr (L"\t ", edit_get_byte (edit, p)))
- #endif /* UTF8 */
- p++;
- for (i = 0; i < size; i++, p++) {
- if (i && indent) {
- if (t[i - 1] == '\n' && c == '\n') {
- #ifndef UTF8
- while (strchr ("\t ", edit_get_byte (edit, p)))
- #else /* UTF8 */
- while (wcschr (L"\t ", edit_get_byte (edit, p)))
- #endif /* UTF8 */
- p++;
- } else if (t[i - 1] == '\n') {
- long curs;
- edit_cursor_move (edit, p - edit->curs1);
- curs = edit->curs1;
- edit_insert_indent (edit, indent);
- if (cursor >= curs)
- cursor += edit->curs1 - p;
- p = edit->curs1;
- } else if (c == '\n') {
- edit_cursor_move (edit, p - edit->curs1);
- #ifndef UTF8
- while (strchr ("\t ", edit_get_byte (edit, p))) {
- #else /* UTF8 */
- while (wcschr (L"\t ", edit_get_byte (edit, p))) {
- #endif /* UTF8 */
- edit_delete (edit);
- if (cursor > edit->curs1)
- cursor--;
- }
- p = edit->curs1;
- }
- }
- c = edit_get_byte (edit, p);
- if (c != t[i])
- replace_at (edit, p, t[i]);
- }
- edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
- }
- static int test_indent (WEdit * edit, long p, long q)
- {
- int indent;
- indent = edit_indent_width (edit, p++);
- if (!indent)
- return 0;
- for (; p < q; p++)
- if (edit_get_byte (edit, p - 1) == '\n')
- if (indent != edit_indent_width (edit, p))
- return 0;
- return indent;
- }
- void
- format_paragraph (WEdit *edit, int force)
- {
- long p, q;
- int size;
- mc_wchar_t *t;
- int indent = 0;
- if (option_word_wrap_line_length < 2)
- return;
- if (line_is_blank (edit, edit->curs_line))
- return;
- p = begin_paragraph (edit, force);
- q = end_paragraph (edit, force);
- indent = test_indent (edit, p, q);
- t = get_paragraph (edit, p, q, indent, &size);
- if (!t)
- return;
- if (!force) {
- int i;
- #ifndef UTF8
- if (strchr (NO_FORMAT_CHARS_START, *t)) {
- #else /* UTF8 */
- if (wcschr (NO_FORMAT_CHARS_START, *t)) {
- #endif /* UTF8 */
- g_free (t);
- return;
- }
- for (i = 0; i < size - 1; i++) {
- if (t[i] == '\n') {
- #ifndef UTF8
- if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
- #else /* UTF8 */
- if (wcschr (NO_FORMAT_CHARS_START "\t", t[i + 1])) {
- #endif /* UTF8 */
- g_free (t);
- return;
- }
- }
- }
- }
- format_this (t, q - p, indent);
- put_paragraph (edit, t, p, indent, size);
- g_free (t);
- /* Scroll left as much as possible to show the formatted paragraph */
- edit_scroll_left (edit, -edit->start_col);
- }
|