1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998 John E. Davis
3 * This file is part of JED editor library source.
4 *
5 * You may distribute this file under the terms the GNU General Public
6 * License. See the file COPYING for more information.
7 */
8 #include "config.h"
9 #include "jed-feat.h"
10
11 /*{{{ Include Files */
12
13 #include <stdio.h>
14 #include <slang.h>
15
16 #include "jdmacros.h"
17
18 #include <string.h>
19 #include <ctype.h>
20 #include "buffer.h"
21 #include "ins.h"
22 #include "ledit.h"
23 #include "text.h"
24 #include "screen.h"
25 #include "cmds.h"
26 #include "paste.h"
27 #include "misc.h"
28 #include "kanji.h"
29
30 /*}}}*/
31
32 /* This routine deletes multiple spaces except those following a period, '?'
33 * or a '!'.
34 Returns the address of beginning of non whitespace */
text_format_line(void)35 unsigned char *text_format_line(void) /*{{{*/
36 {
37 unsigned char *p, *p1;
38 int min;
39
40 p = CLine->data;
41 Point = 0;
42
43 while(((*p == '\t') || (*p == ' ')) && (Point < CLine->len)) p++, Point++;
44 min = Point;
45
46 Point = CLine->len - 1;
47 if (Point < 0) Point = 0;
48 p = CLine->data + Point;
49
50 while (Point > min)
51 {
52 if ((*p == ' ') || (*p == '\t'))
53 {
54 Point--; p--;
55 p1 = p - 1;
56 if (((*p == ' ') || (*p == '\t')) && (Point > min)
57 && (*p1 != '.') && (*p1 != '?') && (*p1 != '!'))
58 {
59 del();
60 if (*p == '\t') *p = ' ';
61 }
62 }
63 else
64 {
65 Point--; p--;
66 }
67 }
68 return(CLine->data + min);
69 }
70
71 /*}}}*/
72
wrap_line1(int format)73 static int wrap_line1(int format) /*{{{*/
74 {
75 unsigned char *p, *pmin, *pmax;
76 int col;
77
78 if (format) pmin = text_format_line(); else pmin = CLine->data;
79 eol();
80 pmax = CLine->data + Point;
81 col = calculate_column();
82 if (col <= Jed_Wrap_Column)
83 {
84 return(0);
85 }
86
87 point_column(Jed_Wrap_Column +1);
88 p = CLine->data + Point;
89 if (p == pmax) return (0);
90
91 p = CLine->data + Point;
92 while(p > pmin)
93 {
94 if ((*p == ' ') || (*p == '\t')) break;
95 #if 1 /* NOT_KANJI_NEW_STUFF_BETA */
96 if (iskanji(*p) && !iskanji2nd(pmin, p - pmin))
97 {
98 if ((p != (CLine->data + Point)) && ((p+2) != pmax)) p += 2;
99 break;
100 }
101 #endif
102 p--;
103 }
104
105 if (p == pmin)
106 {
107 /* that failed, so go the other way */
108 p = CLine->data + CLine->len;
109 while(pmin < p)
110 {
111 if ((*pmin == ' ') || (*pmin == '\t')) break;
112 pmin++;
113 }
114 if (p == pmin) return(0);
115 p = pmin;
116 }
117
118 Point = (int) (p - CLine->data);
119 trim_whitespace();
120 newline();
121 CLine = CLine->prev; LineNum--;
122 return(1);
123 }
124
125 /*}}}*/
126
wrap_line(int format)127 void wrap_line(int format) /*{{{*/
128 {
129 push_spot();
130 wrap_line1(format);
131 pop_spot();
132 }
133
134 /*}}}*/
135
136 /* Here a paragraph follows either an indentation, a '\\' char or two
137 '\n' chars. or a '%' char since tex uses this */
is_paragraph_sep(void)138 static int is_paragraph_sep(void) /*{{{*/
139 {
140 unsigned char *p;
141 int ret;
142 p = CLine->data;
143
144 if (CBuf->par_sep != NULL)
145 {
146 SLexecute_function(CBuf->par_sep);
147 (void) SLang_pop_integer(&ret);
148 if (SLang_Error)
149 {
150 CBuf->par_sep = NULL;
151 ret = 1;
152 }
153 return ret;
154 }
155 if ((*p == '\n') || (*p == '\\') || (*p == '%')) return(1);
156 return(0);
157 }
158
159 /*}}}*/
160
backward_paragraph(void)161 int backward_paragraph(void) /*{{{*/
162 {
163 Line *prev = CLine->prev;
164 int ro = CBuf->flags & READ_ONLY;
165
166 if (NULL == CBuf->par_sep)
167 {
168 CBuf->par_sep = SLang_get_function("is_paragraph_separator");
169 }
170
171 Point = 0;
172 if (prev == NULL) return(0);
173 CLine = prev; LineNum--;
174
175 while(1)
176 {
177 eol();
178 if (!ro) trim_whitespace();
179 if (is_paragraph_sep() || (CLine->prev == NULL)) break;
180 CLine = CLine->prev; LineNum--;
181 }
182 Point = 0;
183 return(1);
184 }
185
186 /*}}}*/
187
forward_paragraph(void)188 int forward_paragraph(void) /*{{{*/
189 {
190 int ro = CBuf->flags & READ_ONLY;
191
192 if (NULL == CBuf->par_sep)
193 {
194 CBuf->par_sep = SLang_get_function("is_paragraph_separator");
195 }
196
197 while(1)
198 {
199 if (CLine->next == NULL) break;
200 CLine = CLine->next; LineNum++;
201 eol();
202 if (!ro) trim_whitespace();
203 if (is_paragraph_sep()) break;
204 }
205
206 eol();
207 return(1);
208 }
209
210 /*}}}*/
211
212 /* format paragraph and if Prefix argument justify_hook is called. */
text_format_paragraph()213 int text_format_paragraph () /*{{{*/
214 {
215 unsigned char *p, *kp;
216 int n, col;
217 int ch, pch;
218 Line *end, *beg, *next;
219
220 CHECK_READ_ONLY
221 push_spot();
222 if (is_paragraph_sep())
223 {
224 pop_spot();
225 return(0);
226 }
227
228 /* if (CBuf->modes != WRAP_MODE) return(0); */
229
230 get_current_indent(&n);
231
232 /* find end */
233 forward_paragraph();
234 if (CLine->next == NULL) end = NULL;
235 else
236 {
237 end = CLine;
238 }
239
240 /* find paragraph start */
241 backward_paragraph();
242 if (is_paragraph_sep() && (CLine->next != NULL))
243 {
244 CLine = CLine->next; LineNum++;
245 }
246 beg = CLine;
247 Point = 0;
248
249 /* Now loop formatting as we go until the end is reached */
250 while(CLine != end)
251 {
252 eol();
253 if (CLine != beg) indent_to(n);
254 if (wrap_line1(1))
255 {
256 CLine = CLine->next;
257 LineNum++;
258 indent_to(n);
259 continue;
260 }
261 else if (CLine->next == end) break;
262
263 next = CLine->next;
264 if (next != end)
265 {
266 /* Now count the length of the word on the next line. */
267 CLine = next; LineNum++;
268 Point = 0;
269 trim_whitespace();
270 p = CLine->data;
271 while((*p > ' ') && (p - CLine->data < CLine->len)) p++;
272
273 #if 1 /* test of Yanagawa's patch */
274 kp = CLine->data;
275 ch = *kp;
276 while((iskanji(ch)) && (CLine->prev->len + (kp - CLine->data) < Jed_Wrap_Column - 1))
277 {
278 kp += 2;
279 ch = *kp;
280 }
281 kp -= 2;
282 if (kp - CLine->data > 0)
283 p = p < kp ? p : kp;
284 #endif
285 CLine = CLine->prev; LineNum--;
286 eol();
287
288 col = calculate_column();
289 if ((p - next->data) + col < Jed_Wrap_Column - 1)
290 {
291 del();
292 if (!iskanji(*(CLine->data + Point)) && !iskanji2nd(CLine->data, Point - 1))
293 ins(' ');
294 }
295 else
296 {
297 CLine = CLine->next;
298 LineNum++;
299 }
300 }
301 }
302 if (Repeat_Factor != NULL)
303 {
304 SLang_run_hooks("format_paragraph_hook", 0);
305 Repeat_Factor = NULL;
306 }
307 pop_spot();
308 return(1);
309 }
310
311 /*}}}*/
312
narrow_paragraph(void)313 int narrow_paragraph(void) /*{{{*/
314 {
315 int wrap, n;
316
317 CHECK_READ_ONLY
318 /* if (CBuf->modes != WRAP_MODE) return(0); */
319 get_current_indent(&n);
320 wrap = Jed_Wrap_Column;
321 if (wrap - n <= wrap/2) return(0);
322 Jed_Wrap_Column -= n;
323 text_format_paragraph();
324 Jed_Wrap_Column = wrap;
325 return(1);
326 }
327
328 /*}}}*/
329
center_line(void)330 int center_line(void) /*{{{*/
331 {
332 unsigned char *p, *pmax;
333 int len;
334
335 CHECK_READ_ONLY
336 push_spot();
337 (void) eol_cmd();
338 p = CLine->data;
339 pmax = p + CLine->len;
340
341 while(p < pmax)
342 {
343 if (*p > ' ') break;
344 p++;
345 }
346 if ((len = (int)(pmax - p)) < 0) len = 0;
347 if ((len = (Jed_Wrap_Column - len) / 2) < 0) len = 0;
348 indent_to(len);
349 pop_spot();
350 return(1);
351 }
352
353 /*}}}*/
354
text_smart_quote(void)355 int text_smart_quote(void) /*{{{*/
356 {
357 unsigned char c;
358 int upd, last;
359
360 /* Force a screen update. This help syntax highlighting */
361 JWindow->trashed = 1;
362
363 if (Point) c = *(CLine->data + (Point - 1)); else c = 0;
364 if (!(CBuf->modes & WRAP_MODE) || (c == '\\')) return ins_char_cmd();
365
366 last = SLang_Last_Key_Char;
367 if ((c == '(') || (c == '[') || (c == '{') || (c <= ' ') || !Point)
368 SLang_Last_Key_Char = '`';
369 else
370 SLang_Last_Key_Char = '\'';
371
372 upd = ins_char_cmd();
373 if (last == '"') upd = ins_char_cmd();
374 SLang_Last_Key_Char = last;
375 return upd;
376 }
377
378 /*}}}*/
379
380 char Jed_Word_Range[256];
define_word(char * w)381 void define_word(char *w) /*{{{*/
382 {
383 strncpy(Jed_Word_Range, w, sizeof (Jed_Word_Range));
384 Jed_Word_Range[sizeof(Jed_Word_Range) - 1] = 0;
385 }
386
387 /*}}}*/
388
jed_get_word_chars(void)389 char *jed_get_word_chars (void)
390 {
391 return Jed_Word_Range;
392 }
393
394
395 /* capitalize region does not really work since it involves words, etc... */
transform_region(int * what)396 void transform_region(int *what) /*{{{*/
397 {
398 int pnt, n;
399 Line *line;
400 unsigned char *p;
401
402 CHECK_READ_ONLY_VOID
403 if (!check_region(&Number_One)) return; /* spot pushed */
404
405 pnt = Point;
406 line = CLine;
407 pop_mark(&Number_One);
408
409 p = CLine->data + Point;
410 while (1)
411 {
412 if (line == CLine) n = pnt; else n = CLine->len;
413
414 switch (*what)
415 {
416 case 'u':
417 while (Point < n)
418 {
419 p = CLine->data + Point;
420 if(iskanji(*p)) Point++;
421 else replace_char(UPPER_CASE(*p));
422 Point++;
423 }
424 break;
425
426 case 'c':
427 if (Point >= n)
428 break;
429 p = CLine->data + Point;
430 if(iskanji(*p)) Point++;
431 else replace_char(UPPER_CASE(*p));
432 Point++;
433 p = CLine->data + Point;
434 /* drop through */
435
436 case 'd':
437 while (Point < n)
438 {
439 p = CLine->data + Point;
440 if(iskanji(*p)) Point++;
441 else replace_char(LOWER_CASE(*p));
442 Point++;
443 }
444 break;
445
446 default:
447 while (Point < n)
448 {
449 p = CLine->data + Point;
450 if(iskanji(*p)) Point++;
451 else replace_char((unsigned char)CHANGE_CASE(*p));
452 Point++;
453 }
454 break;
455 }
456
457
458 if (line == CLine) break;
459 CLine = CLine->next;
460 LineNum++;
461 Point = 0;
462 p = CLine->data;
463 }
464 pop_spot();
465 /* mark_buffer_modified(&Number_One); */
466 }
467
468 /*}}}*/
469
skip_word_chars(void)470 void skip_word_chars(void) /*{{{*/
471 {
472 skip_chars1(Jed_Word_Range, 0);
473 }
474
475 /*}}}*/
476
skip_non_word_chars(void)477 void skip_non_word_chars(void) /*{{{*/
478 {
479 skip_chars1(Jed_Word_Range, 1);
480 }
481
482 /*}}}*/
483
bskip_word_chars(void)484 void bskip_word_chars(void) /*{{{*/
485 {
486 bskip_chars1(Jed_Word_Range, 0);
487 }
488
489 /*}}}*/
490
bskip_non_word_chars(void)491 void bskip_non_word_chars(void) /*{{{*/
492 {
493 bskip_chars1(Jed_Word_Range, 1);
494 }
495
496 /*}}}*/
497
498