Updated italian translatio
[midnight-commander.git] / edit / wordproc.c
blobb7d43aa142424fcec77e07f521f4480557ccaa14
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"
23 #include "edit-widget.h"
25 #define tab_width option_tab_spacing
27 #define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
28 #define FONT_MEAN_WIDTH 1
30 static long
31 line_start (WEdit *edit, long line)
33 long p, l;
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);
43 p = edit_bol (edit, p);
44 while (strchr ("\t ", 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;
71 * Find the start of the current paragraph for the purpose of formatting.
72 * Return position in the file.
74 static long
75 begin_paragraph (WEdit *edit, int force)
77 int i;
78 for (i = edit->curs_line - 1; i >= 0; i--) {
79 if (line_is_blank (edit, i)) {
80 i++;
81 break;
83 if (force) {
84 if (bad_line_start (edit, line_start (edit, i))) {
85 i++;
86 break;
90 return edit_move_backward (edit, edit_bol (edit, edit->curs1),
91 edit->curs_line - i);
95 * Find the end of the current paragraph for the purpose of formatting.
96 * Return position in the file.
98 static long
99 end_paragraph (WEdit *edit, int force)
101 int i;
102 for (i = edit->curs_line + 1; i <= edit->total_lines; i++) {
103 if (line_is_blank (edit, i)) {
104 i--;
105 break;
107 if (force)
108 if (bad_line_start (edit, line_start (edit, i))) {
109 i--;
110 break;
113 return edit_eol (edit,
114 edit_move_forward (edit, edit_bol (edit, edit->curs1),
115 i - edit->curs_line, 0));
118 static unsigned char *
119 get_paragraph (WEdit *edit, long p, long q, int indent, int *size)
121 unsigned char *s, *t;
122 #if 0
123 t = g_malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length +
124 10);
125 #else
126 t = g_malloc (2 * (q - p) + 100);
127 #endif
128 if (!t)
129 return 0;
130 for (s = t; p < q; p++, s++) {
131 if (indent)
132 if (edit_get_byte (edit, p - 1) == '\n')
133 while (strchr ("\t ", edit_get_byte (edit, p)))
134 p++;
135 *s = edit_get_byte (edit, p);
137 *size = (unsigned long) s - (unsigned long) t;
138 t[*size] = '\n';
139 return t;
142 static void strip_newlines (unsigned char *t, int size)
144 unsigned char *p = t;
145 while (size--) {
146 *p = *p == '\n' ? ' ' : *p;
147 p++;
152 This is a copy of the function
153 int calc_text_pos (WEdit * edit, long b, long *q, int l)
154 in propfont.c :(
155 It calculates the number of chars in a line specified to length l in pixels
157 static inline int next_tab_pos (int x)
159 return x += tab_width - x % tab_width;
161 static int line_pixel_length (unsigned char *t, long b, int l)
163 int x = 0, c, xn = 0;
164 for (;;) {
165 c = t[b];
166 switch (c) {
167 case '\n':
168 return b;
169 case '\t':
170 xn = next_tab_pos (x);
171 break;
172 default:
173 xn = x + 1;
174 break;
176 if (xn > l)
177 break;
178 x = xn;
179 b++;
181 return b;
184 /* find the start of a word */
185 static int next_word_start (unsigned char *t, int q, int size)
187 int i;
188 for (i = q;; i++) {
189 switch (t[i]) {
190 case '\n':
191 return -1;
192 case '\t':
193 case ' ':
194 for (;; i++) {
195 if (t[i] == '\n')
196 return -1;
197 if (t[i] != ' ' && t[i] != '\t')
198 return i;
200 break;
205 /* find the start of a word */
206 static int word_start (unsigned char *t, int q, int size)
208 int i = q;
209 if (t[q] == ' ' || t[q] == '\t')
210 return next_word_start (t, q, size);
211 for (;;) {
212 int c;
213 if (!i)
214 return -1;
215 c = t[i - 1];
216 if (c == '\n')
217 return -1;
218 if (c == ' ' || c == '\t')
219 return i;
220 i--;
224 /* replaces ' ' with '\n' to properly format a paragraph */
225 static void format_this (unsigned char *t, int size, int indent)
227 int q = 0, ww;
228 strip_newlines (t, size);
229 ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
230 if (ww < FONT_MEAN_WIDTH * 2)
231 ww = FONT_MEAN_WIDTH * 2;
232 for (;;) {
233 int p;
234 q = line_pixel_length (t, q, ww);
235 if (q > size)
236 break;
237 if (t[q] == '\n')
238 break;
239 p = word_start (t, q, size);
240 if (p == -1)
241 q = next_word_start (t, q, size); /* Return the end of the word if the beginning
242 of the word is at the beginning of a line
243 (i.e. a very long word) */
244 else
245 q = p;
246 if (q == -1) /* end of paragraph */
247 break;
248 if (q)
249 t[q - 1] = '\n';
253 static void replace_at (WEdit * edit, long q, int c)
255 edit_cursor_move (edit, q - edit->curs1);
256 edit_delete (edit);
257 edit_insert_ahead (edit, c);
260 /* replaces a block of text */
261 static void put_paragraph (WEdit * edit, unsigned char *t, long p, long q, int indent, int size)
263 long cursor;
264 int i, c = 0;
265 cursor = edit->curs1;
266 if (indent)
267 while (strchr ("\t ", edit_get_byte (edit, p)))
268 p++;
269 for (i = 0; i < size; i++, p++) {
270 if (i && indent) {
271 if (t[i - 1] == '\n' && c == '\n') {
272 while (strchr ("\t ", edit_get_byte (edit, p)))
273 p++;
274 } else if (t[i - 1] == '\n') {
275 long curs;
276 edit_cursor_move (edit, p - edit->curs1);
277 curs = edit->curs1;
278 edit_insert_indent (edit, indent);
279 if (cursor >= curs)
280 cursor += edit->curs1 - p;
281 p = edit->curs1;
282 } else if (c == '\n') {
283 edit_cursor_move (edit, p - edit->curs1);
284 while (strchr ("\t ", edit_get_byte (edit, p))) {
285 edit_delete (edit);
286 if (cursor > edit->curs1)
287 cursor--;
289 p = edit->curs1;
292 c = edit_get_byte (edit, p);
293 if (c != t[i])
294 replace_at (edit, p, t[i]);
296 edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
299 static int test_indent (WEdit * edit, long p, long q)
301 int indent;
302 indent = edit_indent_width (edit, p++);
303 if (!indent)
304 return 0;
305 for (; p < q; p++)
306 if (edit_get_byte (edit, p - 1) == '\n')
307 if (indent != edit_indent_width (edit, p))
308 return 0;
309 return indent;
312 void
313 format_paragraph (WEdit *edit, int force)
315 long p, q;
316 int size;
317 unsigned char *t;
318 int indent = 0;
319 if (option_word_wrap_line_length < 2)
320 return;
321 if (line_is_blank (edit, edit->curs_line))
322 return;
323 p = begin_paragraph (edit, force);
324 q = end_paragraph (edit, force);
325 indent = test_indent (edit, p, q);
326 t = get_paragraph (edit, p, q, indent, &size);
327 if (!t)
328 return;
329 if (!force) {
330 int i;
331 if (strchr (NO_FORMAT_CHARS_START, *t)) {
332 g_free (t);
333 return;
335 for (i = 0; i < size - 1; i++) {
336 if (t[i] == '\n') {
337 if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
338 g_free (t);
339 return;
344 format_this (t, q - p, indent);
345 put_paragraph (edit, t, p, q, indent, size);
346 g_free (t);
348 /* Scroll left as much as possible to show the formatted paragraph */
349 edit_scroll_left (edit, -edit->start_col);