Ticket #1690: mc.ext entry for .djvu
[free-mc.git] / edit / wordproc.c
blobe3c30552b7eb4fa78bfe4095c606c1fae89f5f49
1 /* wordproc.c - word-processor mode for the editor: does dynamic
2 paragraph formatting.
3 Copyright (C) 1996 Paul Sheer
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA.
21 /** \file
22 * \brief Source: word-processor mode for the editor: does dynamic paragraph formatting
23 * \author Paul Sheer
24 * \date 1996
27 #include <config.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <sys/stat.h>
38 #include <stdlib.h>
40 #include "../src/global.h"
42 #include "edit-impl.h"
43 #include "edit-widget.h"
44 #include "../src/main.h" /* option_tab_spacing */
46 #define tab_width option_tab_spacing
48 #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
49 #define FONT_MEAN_WIDTH 1
51 static long
52 line_start (WEdit *edit, long line)
54 long p, l;
56 l = edit->curs_line;
57 p = edit->curs1;
59 if (line < l)
60 p = edit_move_backward (edit, p, l - line);
61 else if (line > l)
62 p = edit_move_forward (edit, p, line - l, 0);
64 p = edit_bol (edit, p);
65 while (strchr ("\t ", edit_get_byte (edit, p)))
66 p++;
67 return p;
70 static int bad_line_start (WEdit * edit, long p)
72 int c;
73 c = edit_get_byte (edit, p);
74 if (c == '.') { /* `...' is acceptable */
75 if (edit_get_byte (edit, p + 1) == '.')
76 if (edit_get_byte (edit, p + 2) == '.')
77 return 0;
78 return 1;
80 if (c == '-') {
81 if (edit_get_byte (edit, p + 1) == '-')
82 if (edit_get_byte (edit, p + 2) == '-')
83 return 0; /* `---' is acceptable */
84 return 1;
86 if (strchr (NO_FORMAT_CHARS_START, c))
87 return 1;
88 return 0;
92 * Find the start of the current paragraph for the purpose of formatting.
93 * Return position in the file.
95 static long
96 begin_paragraph (WEdit *edit, int force)
98 int i;
99 for (i = edit->curs_line - 1; i >= 0; i--) {
100 if (line_is_blank (edit, i)) {
101 i++;
102 break;
104 if (force) {
105 if (bad_line_start (edit, line_start (edit, i))) {
106 i++;
107 break;
111 return edit_move_backward (edit, edit_bol (edit, edit->curs1),
112 edit->curs_line - i);
116 * Find the end of the current paragraph for the purpose of formatting.
117 * Return position in the file.
119 static long
120 end_paragraph (WEdit *edit, int force)
122 int i;
123 for (i = edit->curs_line + 1; i <= edit->total_lines; i++) {
124 if (line_is_blank (edit, i)) {
125 i--;
126 break;
128 if (force)
129 if (bad_line_start (edit, line_start (edit, i))) {
130 i--;
131 break;
134 return edit_eol (edit,
135 edit_move_forward (edit, edit_bol (edit, edit->curs1),
136 i - edit->curs_line, 0));
139 static unsigned char *
140 get_paragraph (WEdit *edit, long p, long q, int indent, int *size)
142 unsigned char *s, *t;
143 #if 0
144 t = g_malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length +
145 10);
146 #else
147 t = g_malloc (2 * (q - p) + 100);
148 #endif
149 if (!t)
150 return 0;
151 for (s = t; p < q; p++, s++) {
152 if (indent)
153 if (edit_get_byte (edit, p - 1) == '\n')
154 while (strchr ("\t ", edit_get_byte (edit, p)))
155 p++;
156 *s = edit_get_byte (edit, p);
158 *size = (unsigned long) s - (unsigned long) t;
159 t[*size] = '\n';
160 return t;
163 static void strip_newlines (unsigned char *t, int size)
165 unsigned char *p = t;
166 while (size--) {
167 *p = *p == '\n' ? ' ' : *p;
168 p++;
173 This is a copy of the function
174 int calc_text_pos (WEdit * edit, long b, long *q, int l)
175 in propfont.c :(
176 It calculates the number of chars in a line specified to length l in pixels
178 static inline int next_tab_pos (int x)
180 return x += tab_width - x % tab_width;
182 static int line_pixel_length (unsigned char *t, long b, int l)
184 int x = 0, c, xn = 0;
185 for (;;) {
186 c = t[b];
187 switch (c) {
188 case '\n':
189 return b;
190 case '\t':
191 xn = next_tab_pos (x);
192 break;
193 default:
194 xn = x + 1;
195 break;
197 if (xn > l)
198 break;
199 x = xn;
200 b++;
202 return b;
205 static int
206 next_word_start (unsigned char *t, int q, int size)
208 int i;
209 int saw_ws = 0;
211 for (i = q; i < size; i++) {
212 switch (t[i]) {
213 case '\n':
214 return -1;
215 case '\t':
216 case ' ':
217 saw_ws = 1;
218 break;
219 default:
220 if (saw_ws != 0)
221 return i;
222 break;
225 return -1;
228 /* find the start of a word */
229 static int
230 word_start (unsigned char *t, int q, int size)
232 int i = q;
233 if (t[q] == ' ' || t[q] == '\t')
234 return next_word_start (t, q, size);
235 for (;;) {
236 int c;
237 if (!i)
238 return -1;
239 c = t[i - 1];
240 if (c == '\n')
241 return -1;
242 if (c == ' ' || c == '\t')
243 return i;
244 i--;
248 /* replaces ' ' with '\n' to properly format a paragraph */
249 static void format_this (unsigned char *t, int size, int indent)
251 int q = 0, ww;
252 strip_newlines (t, size);
253 ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
254 if (ww < FONT_MEAN_WIDTH * 2)
255 ww = FONT_MEAN_WIDTH * 2;
256 for (;;) {
257 int p;
258 q = line_pixel_length (t, q, ww);
259 if (q > size)
260 break;
261 if (t[q] == '\n')
262 break;
263 p = word_start (t, q, size);
264 if (p == -1)
265 q = next_word_start (t, q, size); /* Return the end of the word if the beginning
266 of the word is at the beginning of a line
267 (i.e. a very long word) */
268 else
269 q = p;
270 if (q == -1) /* end of paragraph */
271 break;
272 if (q)
273 t[q - 1] = '\n';
277 static void replace_at (WEdit * edit, long q, int c)
279 edit_cursor_move (edit, q - edit->curs1);
280 edit_delete (edit, 1);
281 edit_insert_ahead (edit, c);
284 /* replaces a block of text */
285 static void
286 put_paragraph (WEdit * edit, unsigned char *t, long p, int indent, int size)
288 long cursor;
289 int i, c = 0;
290 cursor = edit->curs1;
291 if (indent)
292 while (strchr ("\t ", edit_get_byte (edit, p)))
293 p++;
294 for (i = 0; i < size; i++, p++) {
295 if (i && indent) {
296 if (t[i - 1] == '\n' && c == '\n') {
297 while (strchr ("\t ", edit_get_byte (edit, p)))
298 p++;
299 } else if (t[i - 1] == '\n') {
300 long curs;
301 edit_cursor_move (edit, p - edit->curs1);
302 curs = edit->curs1;
303 edit_insert_indent (edit, indent);
304 if (cursor >= curs)
305 cursor += edit->curs1 - p;
306 p = edit->curs1;
307 } else if (c == '\n') {
308 edit_cursor_move (edit, p - edit->curs1);
309 while (strchr ("\t ", edit_get_byte (edit, p))) {
310 edit_delete (edit, 1);
311 if (cursor > edit->curs1)
312 cursor--;
314 p = edit->curs1;
317 c = edit_get_byte (edit, p);
318 if (c != t[i])
319 replace_at (edit, p, t[i]);
321 edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
324 static int test_indent (WEdit * edit, long p, long q)
326 int indent;
327 indent = edit_indent_width (edit, p++);
328 if (!indent)
329 return 0;
330 for (; p < q; p++)
331 if (edit_get_byte (edit, p - 1) == '\n')
332 if (indent != edit_indent_width (edit, p))
333 return 0;
334 return indent;
337 void
338 format_paragraph (WEdit *edit, int force)
340 long p, q;
341 int size;
342 unsigned char *t;
343 int indent = 0;
344 if (option_word_wrap_line_length < 2)
345 return;
346 if (line_is_blank (edit, edit->curs_line))
347 return;
348 p = begin_paragraph (edit, force);
349 q = end_paragraph (edit, force);
350 indent = test_indent (edit, p, q);
351 t = get_paragraph (edit, p, q, indent, &size);
352 if (!t)
353 return;
354 if (!force) {
355 int i;
356 if (strchr (NO_FORMAT_CHARS_START, *t)) {
357 g_free (t);
358 return;
360 for (i = 0; i < size - 1; i++) {
361 if (t[i] == '\n') {
362 if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
363 g_free (t);
364 return;
369 format_this (t, q - p, indent);
370 put_paragraph (edit, t, p, indent, size);
371 g_free (t);
373 /* Scroll left as much as possible to show the formatted paragraph */
374 edit_scroll_left (edit, -edit->start_col);