1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: word.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2021 Eduardo Chappa
8 * Copyright 2006-2007 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * Program: Word at a time routines
22 * The routines in this file implement commands that work word at a time.
23 * There are all sorts of word mode commands. If I do any sentence and/or
24 * paragraph mode commands, they are likely to be put in this file.
30 int fpnewline(UCS
*quote
);
31 int fillregion(UCS
*qstr
, REGION
*addedregion
);
32 int setquotelevelinregion(int quotelevel
, REGION
*addedregion
);
33 int is_user_separator(UCS c
);
36 /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
37 * line and stop on the first word-break or the beginning of the line. If we
38 * reach the beginning of the line, jump back to the end of the word and start
39 * a new line. Otherwise, break the line at the word-break, eat it, and jump
40 * back to the end of the word.
41 * Returns TRUE on success, FALSE on errors.
46 register int cnt
; /* size of word wrapped to next line */
47 register int bp
; /* index to wrap on */
48 register int first
= -1;
51 if(curwp
->w_doto
<= 0) /* no line to wrap? */
55 for(bp
= cnt
= 0; cnt
< llength(curwp
->w_dotp
) && !bp
; cnt
++){
56 if(ucs4_isspace(lgetc(curwp
->w_dotp
, cnt
).c
)){
58 if(lgetc(curwp
->w_dotp
, cnt
).c
== TAB
){
67 ww
= wcellwidth((UCS
) lgetc(curwp
->w_dotp
, cnt
).c
);
68 wid
+= (ww
>= 0 ? ww
: 1);
73 if(first
> 0 && wid
> fillcol
)
80 /* bp now points to the first character of the next line */
81 cnt
= curwp
->w_doto
- bp
;
84 if(!lnewline()) /* break the line */
88 * if there's a line below, it doesn't start with whitespace
89 * and there's room for this line...
91 if(!(curbp
->b_flag
& BFWRAPOPEN
)
92 && lforw(curwp
->w_dotp
) != curbp
->b_linep
93 && llength(lforw(curwp
->w_dotp
))
94 && !ucs4_isspace(lgetc(lforw(curwp
->w_dotp
), 0).c
)
95 && (llength(curwp
->w_dotp
) + llength(lforw(curwp
->w_dotp
)) < fillcol
)){
96 gotoeol(0, 1); /* then pull text up from below */
97 if(lgetc(curwp
->w_dotp
, curwp
->w_doto
- 1).c
!= ' ')
104 curbp
->b_flag
&= ~BFWRAPOPEN
; /* don't open new line next wrap */
105 /* restore dot (account for NL) */
106 if(cnt
&& !forwchar(0, cnt
< 0 ? cnt
-1 : cnt
))
114 * Move the cursor backward by "n" words. All of the details of motion are
115 * performed by the "backchar" and "forwchar" routines. Error if you try to
116 * move beyond the buffers.
119 backword(int f
, int n
)
122 return (forwword(f
, -n
));
123 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
126 while (inword() == FALSE
) {
127 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
130 while (inword() != FALSE
) {
131 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
135 return (forwchar(FALSE
, 1));
139 * Move the cursor forward by the specified number of words. All of the motion
140 * is done by "forwchar". Error if you try and move beyond the buffer's end.
143 forwword(int f
, int n
)
146 return (backword(f
, -n
));
149 while (inword() != FALSE
) {
150 if (forwchar(FALSE
, 1) == FALSE
)
154 while (inword() == FALSE
) {
155 if (forwchar(FALSE
, 1) == FALSE
)
159 while (inword() != FALSE
) {
160 if (forwchar(FALSE
, 1) == FALSE
)
171 return((c
&& c
<= 0x7f && isalnum((unsigned char) c
))
172 || (c
>= 0xA0 && !SPECIAL_SPACE(c
)));
178 return((c
&& c
<= 0x7f && isalpha((unsigned char) c
))
179 || (c
>= 0xA0 && !SPECIAL_SPACE(c
)));
185 return((c
< 0xff && isspace((unsigned char) c
)) || SPECIAL_SPACE(c
));
191 return !ucs4_isalnum(c
) && !ucs4_isspace(c
);
196 * Move the cursor forward by the specified number of words. As you move,
197 * convert any characters to upper case. Error if you try and move beyond the
198 * end of the buffer. Bound to "M-U".
201 upperword(int f
, int n
)
207 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
208 return(rdonly()); /* we are in read only mode */
212 while (inword() == FALSE
) {
213 if (forwchar(FALSE
, 1) == FALSE
)
216 while (inword() != FALSE
) {
217 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
218 if (c
>='a' && c
<='z') {
219 ac
.c
= (c
-= 'a'-'A');
220 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
223 if (forwchar(FALSE
, 1) == FALSE
)
231 * Move the cursor forward by the specified number of words. As you move
232 * convert characters to lower case. Error if you try and move over the end of
233 * the buffer. Bound to "M-L".
236 lowerword(int f
, int n
)
242 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
243 return(rdonly()); /* we are in read only mode */
247 while (inword() == FALSE
) {
248 if (forwchar(FALSE
, 1) == FALSE
)
251 while (inword() != FALSE
) {
252 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
253 if (c
>='A' && c
<='Z') {
255 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
258 if (forwchar(FALSE
, 1) == FALSE
)
266 * Move the cursor forward by the specified number of words. As you move
267 * convert the first character of the word to upper case, and subsequent
268 * characters to lower case. Error if you try and move past the end of the
269 * buffer. Bound to "M-C".
272 capword(int f
, int n
)
278 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
279 return(rdonly()); /* we are in read only mode */
283 while (inword() == FALSE
) {
284 if (forwchar(FALSE
, 1) == FALSE
)
287 if (inword() != FALSE
) {
288 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
289 if (c
>='a' && c
<='z') {
290 ac
.c
= (c
-= 'a'-'A');
291 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
294 if (forwchar(FALSE
, 1) == FALSE
)
296 while (inword() != FALSE
) {
297 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
298 if (c
>='A' && c
<='Z') {
299 ac
.c
= (c
+= 'a'-'A');
300 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
303 if (forwchar(FALSE
, 1) == FALSE
)
312 * Kill forward by "n" words. Remember the location of dot. Move forward by
313 * the right number of words. Put dot back where it was and issue the kill
314 * command for the right number of characters. Bound to "M-D".
317 delfword(int f
, int n
)
323 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
324 return(rdonly()); /* we are in read only mode */
327 dotp
= curwp
->w_dotp
;
328 doto
= curwp
->w_doto
;
332 while (inword() != FALSE
) {
333 if (forwchar(FALSE
,1) == FALSE
)
338 while (inword() == FALSE
) {
339 if (forwchar(FALSE
, 1) == FALSE
)
344 while (inword() != FALSE
) {
345 if (forwchar(FALSE
, 1) == FALSE
)
351 curwp
->w_dotp
= dotp
;
352 curwp
->w_doto
= doto
;
353 return (ldelete(size
, kinsert
));
357 * Kill backwards by "n" words. Move backwards by the desired number of words,
358 * counting the characters. When dot is finally moved to its resting place,
359 * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
362 delbword(int f
, int n
)
366 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
367 return(rdonly()); /* we are in read only mode */
370 if (backchar(FALSE
, 1) == FALSE
)
374 while (inword() == FALSE
) {
375 if (backchar(FALSE
, 1) == FALSE
)
379 while (inword() != FALSE
) {
380 if (backchar(FALSE
, 1) == FALSE
)
385 if (forwchar(FALSE
, 1) == FALSE
)
387 return (ldelete(size
, kinsert
));
389 #endif /* MAYBELATER */
392 * Return TRUE if the character at dot is a character that is considered to be
398 if(curwp
->w_doto
< llength(curwp
->w_dotp
))
400 if(ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
))
404 else if(ucs4_ispunct(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
)
405 && !is_user_separator(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
))
407 if((curwp
->w_doto
> 0) &&
408 ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
- 1).c
) &&
409 (curwp
->w_doto
+ 1 < llength(curwp
->w_dotp
)) &&
410 ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
+ 1).c
))
422 is_user_separator(UCS c
)
427 for(u
= glo_wordseps
; *u
; u
++)
435 do_quote_match(UCS
*q
, LINE
*l
, UCS
*buf
, size_t buflen
)
441 * The method for determining the quote string is:
442 * 1) strip leading and trailing whitespace from q
443 * 2) add all leading whitespace to buf
445 * 4) if q, append q to buf and any trailing whitespace
446 * 5) repeat steps 3 and 4 as necessary
448 * q in the future could be made to be an array of (UCS *)'s
449 * (">" and whatever the user's quote_string is)
457 /* count leading whitespace as part of the quote */
458 for(j
= 0; j
<= llength(l
) && lgetc(l
, j
).c
== ' ' && j
+1 < buflen
; j
++)
459 buf
[j
] = lgetc(l
, j
).c
;
462 if(q
== NULL
|| *q
== '\0')
465 /* pare down q so it contains no leading or trailing whitespace */
466 for(i
= 0; q
[i
] == ' '; i
++);
468 for(i
= ucs4_strlen(q
); i
> 0 && q
[i
-1] == ' '; i
--);
471 /* for quote strings that are blanks, chop buf to the length of q */
473 if(ucs4_strlen(q
) < buflen
)
474 buf
[ucs4_strlen(q
)] = '\0';
478 while(j
<= llength(l
)){
479 for(i
= qstart
; j
<= llength(l
) && i
< qend
; i
++, j
++)
480 if(q
[i
] != lgetc(l
, j
).c
)
484 if(ucs4_strlen(buf
) + qend
- qstart
< (buflen
- 1))
485 ucs4_strncat(buf
, q
+ qstart
, qend
- qstart
);
489 * if we're this far along, we've matched a quote string,
490 * and should now add the following white space.
492 for(k
= ucs4_strlen(buf
);
493 j
<= llength(l
) && lgetc(l
,j
).c
== ' ' && (k
+ 1 < buflen
);
495 buf
[k
] = lgetc(l
,j
).c
;
505 * Return number of quotes if whatever starts the line matches the quote string
508 quote_match(UCS
*q
, LINE
*gl
, UCS
*bufl
, size_t buflen
)
510 LINE
*nl
= gl
!= curbp
->b_linep
? lforw(gl
) : NULL
;
511 LINE
*pl
= lback(gl
) != curbp
->b_linep
? lback(gl
) : NULL
;
512 UCS bufp
[NSTRING
], bufn
[NSTRING
];
513 int i
, j
, qstart
, qend
;
516 do_quote_match(q
, pl
, bufp
, sizeof(bufp
)); /* previous line */
517 do_quote_match(q
, gl
, bufl
, buflen
); /* given line */
518 do_quote_match(q
, nl
, bufn
, sizeof(bufn
)); /* next line */
520 if(!ucs4_strcmp(bufp
, bufl
) || !ucs4_strcmp(bufl
, bufn
))
521 return ucs4_strlen(bufl
);
523 /* is this line quoted? */
525 /* pare down q so it contains no leading or trailing whitespace */
526 for(i
= 0; q
[i
] == ' '; i
++);
528 for(i
= ucs4_strlen(q
); i
> 0 && q
[i
-1] == ' '; i
--);
530 for(i
= 0; i
< llength(gl
)
532 && lgetc(gl
, i
).c
== q
[i
+qstart
]; i
++);
533 if(i
+ qstart
== qend
)
537 /* compare bufl and bufn */
538 for(i
= 0; bufl
[i
] && bufn
[i
] && bufl
[i
] == bufn
[i
]; i
++);
540 /* go back to last non-space character */
541 for(; i
> 0 && bufl
[i
-1] == ' '; i
--);
543 /* do bufl and bufn differ only in spaces? */
544 for(j
= i
; bufl
[j
] && bufl
[j
] == ' '; j
++);
546 /* if they differ only on trailing spaces, chop bufl to agree with bufn */
548 bufl
[Pmaster
&& quoted_line
? (j
> i
? i
+1 : i
) : i
] = '\0';
550 return ucs4_strlen(bufl
);
554 /* Justify the entire buffer instead of just a paragraph */
556 fillbuf(int f
, int n
)
561 if(curbp
->b_mode
&MDVIEW
){ /* don't allow this command if */
562 return(rdonly()); /* we are in read only mode */
564 else if (fillcol
== 0) { /* no fill column set */
565 mlwrite_utf8("No fill column set", NULL
);
569 if((lastflag
& CFFILL
) && (lastflag
& CFFLBF
)){
570 /* no use doing a full justify twice */
571 thisflag
|= (CFFLBF
| CFFILL
);
575 /* record the pointer of the last line */
576 if(gotoeob(FALSE
, 1) == FALSE
)
579 eobline
= curwp
->w_dotp
; /* last line of buffer */
580 if(!llength(eobline
))
581 eobline
= lback(eobline
);
583 /* and back to the beginning of the buffer */
586 thisflag
|= CFFLBF
; /* CFFILL also gets set in fillpara */
591 curwp
->w_flag
|= WFMODE
;
594 * clear the kill buffer, that's where we'll store undo
595 * information, we can't do the fill buffer because
596 * fillpara relies on its contents
600 getregion(®ion
, eobline
, llength(eobline
));
602 /* Put full message in the kill buffer for undo */
603 if(!ldelete(region
.r_size
, kinsert
))
606 /* before yank'ing, clear lastflag so we don't just unjustify */
607 lastflag
&= ~(CFFLBF
| CFFILL
);
609 /* Now in kill buffer, bring back text to use in fillpara */
614 /* call fillpara until we're at the end of the buffer */
615 while(curwp
->w_dotp
!= curbp
->b_linep
)
616 if(!(fillpara(FALSE
, 1)))
624 * Fill the current paragraph according to the current fill column
627 fillpara(int f
, int n
)
629 UCS
*qstr
, qstr2
[NSTRING
], c
;
634 if(curbp
->b_mode
&MDVIEW
){ /* don't allow this command if */
635 return(rdonly()); /* we are in read only mode */
637 else if (fillcol
== 0) { /* no fill column set */
638 mlwrite_utf8("No fill column set", NULL
);
641 else if(curwp
->w_dotp
== curbp
->b_linep
&& !curwp
->w_markp
) /* don't wrap! */
645 * If there is already a region set, then we may use it
646 * instead of the current paragraph.
651 KEYMENU menu_justify
[12];
654 for(k
= 0; k
< 12; k
++){
655 menu_justify
[k
].name
= NULL
;
656 KS_OSDATASET(&menu_justify
[k
], KS_NONE
);
659 menu_justify
[1].name
= "R";
660 menu_justify
[1].label
= "[" N_("Region") "]";
661 menu_justify
[6].name
= "^C";
662 menu_justify
[6].label
= N_("Cancel");
663 menu_justify
[7].name
= "P";
664 menu_justify
[7].label
= N_("Paragraph");
665 menu_justify
[2].name
= "Q";
666 menu_justify
[2].label
= N_("Quotelevel");
668 wkeyhelp(menu_justify
); /* paint menu */
671 curwp
->w_flag
|= WFMODE
;
673 strncpy(prompt
, "justify Region, Paragraph; or fix Quotelevel ? ", sizeof(prompt
));
674 prompt
[sizeof(prompt
)-1] = '\0';
675 mlwrite_utf8(prompt
, NULL
);
679 switch(c
= GetKey()){
681 case (CTRL
|'C') : /* Bail out! */
683 pputs_utf8(_("ABORT"), 1);
688 case (CTRL
|'M') : /* default */
692 pputs_utf8(_("Region"), 1);
699 pputs_utf8(_("Paragraph"), 1);
706 case '0' : case '1' : case '2' : case '3' : case '4' :
707 case '5' : case '6' : case '7' : case '8' : case '9' :
708 pputs_utf8(_("Quotelevel"), 1);
717 switch(mlreplyd_utf8("Quote Level ? ", num
, sizeof(num
), QNORML
, NULL
)){
720 quotelevel
= atoi(num
);
722 emlwrite("Quote Level cannot be negative", NULL
);
725 else if(quotelevel
> 20){
726 emlwrite("Quote Level should be less than 20", NULL
);
734 emlwrite("Quote Level should be a number", NULL
);
741 emlwrite("Enter the number of quotes you want before the text", NULL
);
746 emlwrite("Quote Level is a number", NULL
);
754 case '0' : case '1' : case '2' : case '3' : case '4' :
755 case '5' : case '6' : case '7' : case '8' : case '9' :
757 quotelevel
= (int) (c
- '0');
765 if(term
.t_mrow
== 0 && km_popped
== 0){
766 movecursor(term
.t_nrow
-2, 0);
770 wkeyhelp(menu_justify
);
771 mlwrite_utf8(prompt
, NULL
);
773 sgarbk
= TRUE
; /* mark menu dirty */
777 /* else fall through */
791 movecursor(term
.t_nrow
, 0);
806 if(action
== 'R' && curwp
->w_markp
){
807 /* let yank() know that it may be restoring a paragraph */
813 curwp
->w_flag
|= WFMODE
;
815 swap_mark_and_dot_if_mark_comes_first();
817 /* determine if we're justifying quoted text or not */
818 qstr
= quote_match(glo_quote_str
,
819 curwp
->w_doto
> 0 ? curwp
->w_dotp
->l_fp
: curwp
->w_dotp
,
821 && *qstr2
? qstr2
: NULL
;
825 * Fillregion moves dot to the end of the filled region.
827 if(!fillregion(qstr
, &addedregion
))
830 set_last_region_added(&addedregion
);
832 else if(action
== 'P'){
835 * Justfiy the current paragraph.
838 if(curwp
->w_markp
) /* clear mark if already set */
841 if(gotoeop(FALSE
, 1) == FALSE
)
844 /* determine if we're justifying quoted text or not */
845 qstr
= quote_match(glo_quote_str
,
846 curwp
->w_dotp
, qstr2
, NSTRING
)
847 && *qstr2
? qstr2
: NULL
;
849 setmark(0,0); /* mark last line of para */
851 /* jump back to the beginning of the paragraph */
854 /* let yank() know that it may be restoring a paragraph */
855 thisflag
|= (CFFILL
| CFFLPA
);
860 curwp
->w_flag
|= WFMODE
;
862 curwp
->w_doto
= 0; /* start region at beginning of line */
865 * Fillregion moves dot to the end of the filled region.
867 if(!fillregion(qstr
, &addedregion
))
870 set_last_region_added(&addedregion
);
872 /* Leave cursor on first char of first line after justified region */
873 curwp
->w_dotp
= lforw(curwp
->w_dotp
);
877 setmark(0,0); /* clear mark */
879 else if(action
== 'Q'){
880 /* let yank() know that it may be restoring a paragraph */
886 curwp
->w_flag
|= WFHARD
;
888 swap_mark_and_dot_if_mark_comes_first();
890 if(!setquotelevelinregion(quotelevel
, &addedregion
))
893 set_last_region_added(&addedregion
);
904 * The region we're filling is the region from dot to mark.
905 * We cut out that region and then put it back in filled.
906 * The cut out part is saved in the ldelete call and the
907 * reinstalled region is noted in addedregion, so that yank()
908 * can delete it and restore the saved part.
911 fillregion(UCS
*qstr
, REGION
*addedregion
)
913 long c
, sz
, last_char
= 0;
914 int i
, j
, qlen
, same_word
,
915 spaces
, word_len
, word_ind
, line_len
, ww
;
916 int starts_midline
= 0;
917 int ends_midline
= 0;
918 int offset_into_start
;
919 LINE
*line_before_start
, *lp
;
920 UCS line_last
, word
[NSTRING
];
923 /* if region starts midline insert a newline */
924 if(curwp
->w_doto
> 0 && curwp
->w_doto
< llength(curwp
->w_dotp
))
927 /* if region ends midline insert a newline at end */
928 if(curwp
->w_marko
> 0 && curwp
->w_marko
< llength(curwp
->w_markp
))
931 /* cut the paragraph into our fill buffer */
933 if(!getregion(®ion
, curwp
->w_markp
, curwp
->w_marko
))
936 if(!ldelete(region
.r_size
, finsert
))
939 line_before_start
= lback(curwp
->w_dotp
);
940 offset_into_start
= curwp
->w_doto
;
945 /* Now insert it back wrapped */
946 spaces
= word_len
= word_ind
= line_len
= same_word
= 0;
947 qlen
= qstr
? ucs4_strlen(qstr
) : 0;
949 /* Beginning with leading quoting... */
953 ww
= wcellwidth(qstr
[i
]);
954 line_len
+= (ww
>= 0 ? ww
: 1);
955 linsert(1, qstr
[i
++]);
958 line_last
= ' '; /* no word-flush space! */
961 /* remove first leading quotes if any */
965 for(i
= qlen
; (c
= fremove(i
)) == ' ' || c
== TAB
; i
++){
966 linsert(1, line_last
= (UCS
) c
);
967 line_len
+= ((c
== TAB
) ? (~line_len
& 0x07) + 1 : 1);
970 /* then digest the rest... */
971 while((c
= fremove(i
++)) >= 0){
975 /* skip next quote string */
977 while(j
< qlen
&& ((c
= fremove(i
+j
)) == qstr
[j
] || c
== ' '))
993 if(spaces
){ /* flush word? */
994 if((line_len
- qlen
> 0)
995 && line_len
+ word_len
+ 1 > fillcol
996 && ((ucs4_isspace(line_last
))
997 || (linsert(1, ' ')))
999 && (line_len
= fpnewline(qstr
)))
1000 line_last
= ' '; /* no word-flush space! */
1002 if(word_len
){ /* word to write? */
1003 if(line_len
&& !ucs4_isspace(line_last
)){
1004 linsert(1, ' '); /* need padding? */
1008 line_len
+= word_len
;
1009 for(j
= 0; j
< word_ind
; j
++)
1010 linsert(1, line_last
= word
[j
]);
1012 if(spaces
> 1 && strchr(".?!:;\")", line_last
)){
1013 linsert(2, line_last
= ' ');
1017 same_word
= word_len
= word_ind
= 0;
1023 if(word_ind
+ 1 >= NSTRING
){
1024 /* Magic! Fake that we output a wrapped word */
1025 if((line_len
- qlen
> 0) && same_word
== 0){
1026 if(!ucs4_isspace(line_last
))
1028 line_len
= fpnewline(qstr
);
1031 line_len
+= word_len
;
1032 for(j
= 0; j
< word_ind
; j
++)
1033 linsert(1, word
[j
]);
1035 word_len
= word_ind
= 0;
1039 word
[word_ind
++] = (UCS
) c
;
1040 ww
= wcellwidth((UCS
) c
);
1041 word_len
+= (ww
>= 0 ? ww
: 1);
1048 if((line_len
- qlen
> 0) && (line_len
+ word_len
+ 1 > fillcol
) && same_word
== 0){
1049 if(!ucs4_isspace(line_last
))
1051 (void) fpnewline(qstr
);
1053 else if(line_len
&& !ucs4_isspace(line_last
))
1056 for(j
= 0; j
< word_ind
; j
++)
1057 linsert(1, word
[j
]);
1060 if(last_char
== '\n')
1064 (void) fpnewline(qstr
);
1067 * Calculate the size of the region that was added.
1069 swapmark(0,1); /* mark current location after adds */
1070 addedregion
->r_linep
= lforw(line_before_start
);
1071 addedregion
->r_offset
= offset_into_start
;
1072 lp
= addedregion
->r_linep
;
1073 sz
= llength(lp
) - addedregion
->r_offset
;
1074 if(lforw(lp
) != curwp
->w_markp
->l_fp
){
1076 while(lp
!= curwp
->w_markp
->l_fp
){
1077 sz
+= llength(lp
) + 1;
1082 sz
-= llength(curwp
->w_markp
) - curwp
->w_marko
;
1083 addedregion
->r_size
= sz
;
1089 * We want to back up to the end of the original
1090 * region instead of being here after the added newline.
1103 * fpnewline - output a fill paragraph newline mindful of quote string
1106 fpnewline(UCS
*quote
)
1111 for(len
= 0; quote
&& *quote
; quote
++){
1114 ww
= wcellwidth(*quote
);
1115 len
+= (ww
>= 0 ? ww
: 1);
1124 setquotelevelinregion(int quotelevel
, REGION
*addedregion
)
1126 int i
, standards_based
= 0;
1127 int quote_chars
= 0, backuptoprevline
= 0;
1128 int starts_midline
= 0, ends_midline
= 0, offset_into_start
;
1130 UCS qstr_def1
[] = { '>', ' ', 0}, qstr_def2
[] = { '>', 0};
1131 LINE
*lp
, *line_before_start
;
1134 if(curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
1135 return(rdonly()); /* we are in read only mode */
1138 || !ucs4_strcmp(glo_quote_str
, qstr_def1
)
1139 || !ucs4_strcmp(glo_quote_str
, qstr_def2
))
1142 if(!standards_based
){
1143 emlwrite("Quote level setting only works with standard \"> \" quotes", NULL
);
1147 /* if region starts midline insert a newline */
1148 if(curwp
->w_doto
> 0 && curwp
->w_doto
< llength(curwp
->w_dotp
))
1151 /* if region ends midline insert a newline at end */
1152 if(curwp
->w_marko
> 0 && curwp
->w_marko
< llength(curwp
->w_markp
)){
1155 /* count quote chars for re-insertion */
1156 for(i
= 0; i
< llength(curwp
->w_markp
); ++i
)
1157 if(lgetc(curwp
->w_markp
, i
).c
!= '>')
1162 else if(curwp
->w_marko
== 0)
1165 /* find the size of the region */
1166 getregion(®ion
, curwp
->w_markp
, curwp
->w_marko
);
1168 /* cut the paragraph into our fill buffer */
1170 if(!ldelete(region
.r_size
, finsert
))
1173 line_before_start
= lback(curwp
->w_dotp
);
1174 offset_into_start
= curwp
->w_doto
;
1176 /* if region starts midline add a newline */
1181 while(fremove(i
) >= 0){
1183 /* remove all quote strs from current line */
1184 if(standards_based
){
1185 while((c
= fremove(i
)) == '>')
1194 /* insert quotelevel quote strs */
1195 if(standards_based
){
1196 linsert(quotelevel
, '>');
1203 /* put back the actual line */
1204 while((c
= fremove(i
++)) >= 0 && c
!= '\n')
1205 linsert(1, (UCS
) c
);
1211 /* if region ends midline add a newline */
1215 linsert(quote_chars
, '>');
1216 if(curwp
->w_doto
< llength(curwp
->w_dotp
)
1217 && lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
!= ' ')
1223 * Calculate the size of the region that was added.
1225 swapmark(0,1); /* mark current location after adds */
1226 addedregion
->r_linep
= lforw(line_before_start
);
1227 addedregion
->r_offset
= offset_into_start
;
1228 lp
= addedregion
->r_linep
;
1229 sz
= llength(lp
) - addedregion
->r_offset
;
1230 if(lforw(lp
) != curwp
->w_markp
->l_fp
){
1232 while(lp
!= curwp
->w_markp
->l_fp
){
1233 sz
+= llength(lp
) + 1;
1238 sz
-= llength(curwp
->w_markp
) - curwp
->w_marko
;
1239 addedregion
->r_size
= sz
;
1244 * This puts us at the end of the quoted region instead
1245 * of on the following line. This makes it convenient
1246 * for the user to follow a quotelevel adjustment with
1247 * a Justify if desired.
1249 if(backuptoprevline
){
1254 if(ends_midline
){ /* doesn't need fixing otherwise */