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