Revert second bunch of mhl patches (see 9b9cab58749217101ab16504a77efb301812cfbf)
[midnight-commander.git] / edit / wordproc.c
blobdb64a0a542467fe9be05d777313f1a8ce35f683f
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 #include <config.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <sys/types.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <stdlib.h>
35 #include <mhl/memory.h>
37 #include "../src/global.h"
39 #include "edit.h"
40 #include "edit-widget.h"
42 #define tab_width option_tab_spacing
44 #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
45 #define FONT_MEAN_WIDTH 1
47 static long
48 line_start (WEdit *edit, long line)
50 long p, l;
52 l = edit->curs_line;
53 p = edit->curs1;
55 if (line < l)
56 p = edit_move_backward (edit, p, l - line);
57 else if (line > l)
58 p = edit_move_forward (edit, p, line - l, 0);
60 p = edit_bol (edit, p);
61 while (strchr ("\t ", edit_get_byte (edit, p)))
62 p++;
63 return p;
66 static int bad_line_start (WEdit * edit, long p)
68 int c;
69 c = edit_get_byte (edit, p);
70 if (c == '.') { /* `...' is acceptable */
71 if (edit_get_byte (edit, p + 1) == '.')
72 if (edit_get_byte (edit, p + 2) == '.')
73 return 0;
74 return 1;
76 if (c == '-') {
77 if (edit_get_byte (edit, p + 1) == '-')
78 if (edit_get_byte (edit, p + 2) == '-')
79 return 0; /* `---' is acceptable */
80 return 1;
82 if (strchr (NO_FORMAT_CHARS_START, c))
83 return 1;
84 return 0;
88 * Find the start of the current paragraph for the purpose of formatting.
89 * Return position in the file.
91 static long
92 begin_paragraph (WEdit *edit, int force)
94 int i;
95 for (i = edit->curs_line - 1; i >= 0; i--) {
96 if (line_is_blank (edit, i)) {
97 i++;
98 break;
100 if (force) {
101 if (bad_line_start (edit, line_start (edit, i))) {
102 i++;
103 break;
107 return edit_move_backward (edit, edit_bol (edit, edit->curs1),
108 edit->curs_line - i);
112 * Find the end of the current paragraph for the purpose of formatting.
113 * Return position in the file.
115 static long
116 end_paragraph (WEdit *edit, int force)
118 int i;
119 for (i = edit->curs_line + 1; i <= edit->total_lines; i++) {
120 if (line_is_blank (edit, i)) {
121 i--;
122 break;
124 if (force)
125 if (bad_line_start (edit, line_start (edit, i))) {
126 i--;
127 break;
130 return edit_eol (edit,
131 edit_move_forward (edit, edit_bol (edit, edit->curs1),
132 i - edit->curs_line, 0));
135 static unsigned char *
136 get_paragraph (WEdit *edit, long p, long q, int indent, int *size)
138 unsigned char *s, *t;
139 #if 0
140 t = g_malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length +
141 10);
142 #else
143 t = g_malloc (2 * (q - p) + 100);
144 #endif
145 if (!t)
146 return 0;
147 for (s = t; p < q; p++, s++) {
148 if (indent)
149 if (edit_get_byte (edit, p - 1) == '\n')
150 while (strchr ("\t ", edit_get_byte (edit, p)))
151 p++;
152 *s = edit_get_byte (edit, p);
154 *size = (unsigned long) s - (unsigned long) t;
155 t[*size] = '\n';
156 return t;
159 static void strip_newlines (unsigned char *t, int size)
161 unsigned char *p = t;
162 while (size--) {
163 *p = *p == '\n' ? ' ' : *p;
164 p++;
169 This is a copy of the function
170 int calc_text_pos (WEdit * edit, long b, long *q, int l)
171 in propfont.c :(
172 It calculates the number of chars in a line specified to length l in pixels
174 static inline int next_tab_pos (int x)
176 return x += tab_width - x % tab_width;
178 static int line_pixel_length (unsigned char *t, long b, int l)
180 int x = 0, c, xn = 0;
181 for (;;) {
182 c = t[b];
183 switch (c) {
184 case '\n':
185 return b;
186 case '\t':
187 xn = next_tab_pos (x);
188 break;
189 default:
190 xn = x + 1;
191 break;
193 if (xn > l)
194 break;
195 x = xn;
196 b++;
198 return b;
201 static int
202 next_word_start (unsigned char *t, int q, int size)
204 int i;
205 int saw_ws = 0;
207 for (i = q; i < size; i++) {
208 switch (t[i]) {
209 case '\n':
210 return -1;
211 case '\t':
212 case ' ':
213 saw_ws = 1;
214 break;
215 default:
216 if (saw_ws != 0)
217 return i;
218 break;
221 return -1;
224 /* find the start of a word */
225 static int
226 word_start (unsigned char *t, int q, int size)
228 int i = q;
229 if (t[q] == ' ' || t[q] == '\t')
230 return next_word_start (t, q, size);
231 for (;;) {
232 int c;
233 if (!i)
234 return -1;
235 c = t[i - 1];
236 if (c == '\n')
237 return -1;
238 if (c == ' ' || c == '\t')
239 return i;
240 i--;
244 /* replaces ' ' with '\n' to properly format a paragraph */
245 static void format_this (unsigned char *t, int size, int indent)
247 int q = 0, ww;
248 strip_newlines (t, size);
249 ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
250 if (ww < FONT_MEAN_WIDTH * 2)
251 ww = FONT_MEAN_WIDTH * 2;
252 for (;;) {
253 int p;
254 q = line_pixel_length (t, q, ww);
255 if (q > size)
256 break;
257 if (t[q] == '\n')
258 break;
259 p = word_start (t, q, size);
260 if (p == -1)
261 q = next_word_start (t, q, size); /* Return the end of the word if the beginning
262 of the word is at the beginning of a line
263 (i.e. a very long word) */
264 else
265 q = p;
266 if (q == -1) /* end of paragraph */
267 break;
268 if (q)
269 t[q - 1] = '\n';
273 static void replace_at (WEdit * edit, long q, int c)
275 edit_cursor_move (edit, q - edit->curs1);
276 edit_delete (edit);
277 edit_insert_ahead (edit, c);
280 /* replaces a block of text */
281 static void
282 put_paragraph (WEdit * edit, unsigned char *t, long p, int indent, int size)
284 long cursor;
285 int i, c = 0;
286 cursor = edit->curs1;
287 if (indent)
288 while (strchr ("\t ", edit_get_byte (edit, p)))
289 p++;
290 for (i = 0; i < size; i++, p++) {
291 if (i && indent) {
292 if (t[i - 1] == '\n' && c == '\n') {
293 while (strchr ("\t ", edit_get_byte (edit, p)))
294 p++;
295 } else if (t[i - 1] == '\n') {
296 long curs;
297 edit_cursor_move (edit, p - edit->curs1);
298 curs = edit->curs1;
299 edit_insert_indent (edit, indent);
300 if (cursor >= curs)
301 cursor += edit->curs1 - p;
302 p = edit->curs1;
303 } else if (c == '\n') {
304 edit_cursor_move (edit, p - edit->curs1);
305 while (strchr ("\t ", edit_get_byte (edit, p))) {
306 edit_delete (edit);
307 if (cursor > edit->curs1)
308 cursor--;
310 p = edit->curs1;
313 c = edit_get_byte (edit, p);
314 if (c != t[i])
315 replace_at (edit, p, t[i]);
317 edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
320 static int test_indent (WEdit * edit, long p, long q)
322 int indent;
323 indent = edit_indent_width (edit, p++);
324 if (!indent)
325 return 0;
326 for (; p < q; p++)
327 if (edit_get_byte (edit, p - 1) == '\n')
328 if (indent != edit_indent_width (edit, p))
329 return 0;
330 return indent;
333 void
334 format_paragraph (WEdit *edit, int force)
336 long p, q;
337 int size;
338 unsigned char *t;
339 int indent = 0;
340 if (option_word_wrap_line_length < 2)
341 return;
342 if (line_is_blank (edit, edit->curs_line))
343 return;
344 p = begin_paragraph (edit, force);
345 q = end_paragraph (edit, force);
346 indent = test_indent (edit, p, q);
347 t = get_paragraph (edit, p, q, indent, &size);
348 if (!t)
349 return;
350 if (!force) {
351 int i;
352 if (strchr (NO_FORMAT_CHARS_START, *t)) {
353 mhl_mem_free (t);
354 return;
356 for (i = 0; i < size - 1; i++) {
357 if (t[i] == '\n') {
358 if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
359 mhl_mem_free (t);
360 return;
365 format_this (t, q - p, indent);
366 put_paragraph (edit, t, p, indent, size);
367 mhl_mem_free (t);
369 /* Scroll left as much as possible to show the formatted paragraph */
370 edit_scroll_left (edit, -edit->start_col);