ooops...
[midnight-commander.git] / edit / wordproc.c
blob2a84b3e99e0e6be36e07c44c9d7acecd3548c458
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., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307, USA.
21 #include <config.h>
22 #include "edit.h"
24 #define tab_width option_tab_spacing
26 int line_is_blank (WEdit * edit, long line);
28 #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
30 static long line_start (WEdit * edit, long line)
32 static long p = -1, l = 0;
33 int c;
34 if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) {
35 l = edit->curs_line;
36 p = edit->curs1;
38 if (line < l)
39 p = edit_move_backward (edit, p, l - line);
40 else if (line > l)
41 p = edit_move_forward (edit, p, line - l, 0);
42 l = line;
43 p = edit_bol (edit, p);
44 while (strchr ("\t ", c = edit_get_byte (edit, p)))
45 p++;
46 return p;
49 static int bad_line_start (WEdit * edit, long p)
51 int c;
52 c = edit_get_byte (edit, p);
53 if (c == '.') { /* `...' is acceptable */
54 if (edit_get_byte (edit, p + 1) == '.')
55 if (edit_get_byte (edit, p + 2) == '.')
56 return 0;
57 return 1;
59 if (c == '-') {
60 if (edit_get_byte (edit, p + 1) == '-')
61 if (edit_get_byte (edit, p + 2) == '-')
62 return 0; /* `---' is acceptable */
63 return 1;
65 if (strchr (NO_FORMAT_CHARS_START, c))
66 return 1;
67 return 0;
70 static long begin_paragraph (WEdit * edit, long p, int force)
72 int i;
73 for (i = edit->curs_line - 1; i > 0; i--) {
74 if (line_is_blank (edit, i)) {
75 i++;
76 break;
78 if (force) {
79 if (bad_line_start (edit, line_start (edit, i))) {
80 i++;
81 break;
85 return edit_move_backward (edit, edit_bol (edit, edit->curs1), edit->curs_line - i);
88 static long end_paragraph (WEdit * edit, long p, int force)
90 int i;
91 for (i = edit->curs_line + 1; i < edit->total_lines; i++) {
92 if (line_is_blank (edit, i)) {
93 i--;
94 break;
96 if (force)
97 if (bad_line_start (edit, line_start (edit, i))) {
98 i--;
99 break;
102 return edit_eol (edit, edit_move_forward (edit, edit_bol (edit, edit->curs1), i - edit->curs_line, 0));
105 static unsigned char *get_paragraph (WEdit * edit, long p, long q, int indent, int *size)
107 unsigned char *s, *t;
108 #if 0
109 t = malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length + 10);
110 #else
111 t = malloc (2 * (q - p) + 100);
112 #endif
113 if (!t)
114 return 0;
115 for (s = t; p < q; p++, s++) {
116 if (indent)
117 if (edit_get_byte (edit, p - 1) == '\n')
118 while (strchr ("\t ", edit_get_byte (edit, p)))
119 p++;
120 *s = edit_get_byte (edit, p);
122 *size = (unsigned long) s - (unsigned long) t;
123 t[*size] = '\n';
124 return t;
127 static void strip_newlines (unsigned char *t, int size)
129 unsigned char *p = t;
130 while (size--) {
131 *p = *p == '\n' ? ' ' : *p;
132 p++;
137 This is a copy of the function
138 int calc_text_pos (WEdit * edit, long b, long *q, int l)
139 in propfont.c :(
140 It calculates the number of chars in a line specified to length l in pixels
142 extern int tab_width;
143 static inline int next_tab_pos (int x)
145 return x += tab_width - x % tab_width;
147 static int line_pixel_length (unsigned char *t, long b, int l)
149 int x = 0, c, xn = 0;
150 for (;;) {
151 c = t[b];
152 switch (c) {
153 case '\n':
154 return b;
155 case '\t':
156 xn = next_tab_pos (x);
157 break;
158 default:
159 xn = x + 1;
160 break;
162 if (xn > l)
163 break;
164 x = xn;
165 b++;
167 return b;
170 /* find the start of a word */
171 static int next_word_start (unsigned char *t, int q, int size)
173 int i;
174 for (i = q;; i++) {
175 switch (t[i]) {
176 case '\n':
177 return -1;
178 case '\t':
179 case ' ':
180 for (;; i++) {
181 if (t[i] == '\n')
182 return -1;
183 if (t[i] != ' ' && t[i] != '\t')
184 return i;
186 break;
191 /* find the start of a word */
192 static int word_start (unsigned char *t, int q, int size)
194 int i = q;
195 if (t[q] == ' ' || t[q] == '\t')
196 return next_word_start (t, q, size);
197 for (;;) {
198 int c;
199 if (!i)
200 return -1;
201 c = t[i - 1];
202 if (c == '\n')
203 return -1;
204 if (c == ' ' || c == '\t')
205 return i;
206 i--;
210 /* replaces ' ' with '\n' to properly format a paragraph */
211 static void format_this (unsigned char *t, int size, int indent)
213 int q = 0, ww;
214 strip_newlines (t, size);
215 ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
216 if (ww < FONT_MEAN_WIDTH * 2)
217 ww = FONT_MEAN_WIDTH * 2;
218 for (;;) {
219 int p;
220 q = line_pixel_length (t, q, ww);
221 if (q > size)
222 break;
223 if (t[q] == '\n')
224 break;
225 p = word_start (t, q, size);
226 if (p == -1)
227 q = next_word_start (t, q, size); /* Return the end of the word if the beginning
228 of the word is at the beginning of a line
229 (i.e. a very long word) */
230 else
231 q = p;
232 if (q == -1) /* end of paragraph */
233 break;
234 if (q)
235 t[q - 1] = '\n';
239 static void replace_at (WEdit * edit, long q, int c)
241 edit_cursor_move (edit, q - edit->curs1);
242 edit_delete (edit);
243 edit_insert_ahead (edit, c);
246 void edit_insert_indent (WEdit * edit, int indent);
248 /* replaces a block of text */
249 static void put_paragraph (WEdit * edit, unsigned char *t, long p, long q, int indent, int size)
251 long cursor;
252 int i, c = 0;
253 cursor = edit->curs1;
254 if (indent)
255 while (strchr ("\t ", edit_get_byte (edit, p)))
256 p++;
257 for (i = 0; i < size; i++, p++) {
258 if (i && indent) {
259 if (t[i - 1] == '\n' && c == '\n') {
260 while (strchr ("\t ", edit_get_byte (edit, p)))
261 p++;
262 } else if (t[i - 1] == '\n') {
263 long curs;
264 edit_cursor_move (edit, p - edit->curs1);
265 curs = edit->curs1;
266 edit_insert_indent (edit, indent);
267 if (cursor >= curs)
268 cursor += edit->curs1 - p;
269 p = edit->curs1;
270 } else if (c == '\n') {
271 edit_cursor_move (edit, p - edit->curs1);
272 while (strchr ("\t ", edit_get_byte (edit, p))) {
273 edit_delete (edit);
274 if (cursor > edit->curs1)
275 cursor--;
277 p = edit->curs1;
280 c = edit_get_byte (edit, p);
281 if (c != t[i])
282 replace_at (edit, p, t[i]);
284 edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
287 int edit_indent_width (WEdit * edit, long p);
289 static int test_indent (WEdit * edit, long p, long q)
291 int indent;
292 indent = edit_indent_width (edit, p++);
293 if (!indent)
294 return 0;
295 for (; p < q; p++)
296 if (edit_get_byte (edit, p - 1) == '\n')
297 if (indent != edit_indent_width (edit, p))
298 return 0;
299 return indent;
302 void format_paragraph (WEdit * edit, int force)
304 long p, q;
305 int size;
306 unsigned char *t;
307 int indent = 0;
308 if (option_word_wrap_line_length < 2)
309 return;
310 if (line_is_blank (edit, edit->curs_line))
311 return;
312 p = begin_paragraph (edit, edit->curs1, force);
313 q = end_paragraph (edit, edit->curs1, force);
314 indent = test_indent (edit, p, q);
315 t = get_paragraph (edit, p, q, indent, &size);
316 if (!t)
317 return;
318 if (!force) {
319 int i;
320 if (strchr (NO_FORMAT_CHARS_START, *t)) {
321 free (t);
322 return;
324 for (i = 0; i < size - 1; i++) {
325 if (t[i] == '\n') {
326 if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
327 free (t);
328 return;
333 format_this (t, q - p, indent);
334 put_paragraph (edit, t, p, q, indent, size);
335 free (t);