2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * Program: Word at a time routines
18 * The routines in this file implement commands that work word at a time.
19 * There are all sorts of word mode commands. If I do any sentence and/or
20 * paragraph mode commands, they are likely to be put in this file.
26 int fpnewline(UCS
*quote
);
27 int fillregion(UCS
*qstr
, REGION
*addedregion
);
28 int setquotelevelinregion(int quotelevel
, REGION
*addedregion
);
29 int is_user_separator(UCS c
);
32 /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
33 * line and stop on the first word-break or the beginning of the line. If we
34 * reach the beginning of the line, jump back to the end of the word and start
35 * a new line. Otherwise, break the line at the word-break, eat it, and jump
36 * back to the end of the word.
37 * Returns TRUE on success, FALSE on errors.
42 register int cnt
; /* size of word wrapped to next line */
43 register int bp
; /* index to wrap on */
44 register int first
= -1;
47 if(curwp
->w_doto
<= 0) /* no line to wrap? */
51 for(bp
= cnt
= 0; cnt
< llength(curwp
->w_dotp
) && !bp
; cnt
++){
52 if(ucs4_isspace(lgetc(curwp
->w_dotp
, cnt
).c
)){
54 if(lgetc(curwp
->w_dotp
, cnt
).c
== TAB
){
63 ww
= wcellwidth((UCS
) lgetc(curwp
->w_dotp
, cnt
).c
);
64 wid
+= (ww
>= 0 ? ww
: 1);
69 if(first
> 0 && wid
> fillcol
)
76 /* bp now points to the first character of the next line */
77 cnt
= curwp
->w_doto
- bp
;
80 if(!lnewline()) /* break the line */
84 * if there's a line below, it doesn't start with whitespace
85 * and there's room for this line...
87 if(!(curbp
->b_flag
& BFWRAPOPEN
)
88 && lforw(curwp
->w_dotp
) != curbp
->b_linep
89 && llength(lforw(curwp
->w_dotp
))
90 && !ucs4_isspace(lgetc(lforw(curwp
->w_dotp
), 0).c
)
91 && (llength(curwp
->w_dotp
) + llength(lforw(curwp
->w_dotp
)) < fillcol
)){
92 gotoeol(0, 1); /* then pull text up from below */
93 if(lgetc(curwp
->w_dotp
, curwp
->w_doto
- 1).c
!= ' ')
100 curbp
->b_flag
&= ~BFWRAPOPEN
; /* don't open new line next wrap */
101 /* restore dot (account for NL) */
102 if(cnt
&& !forwchar(0, cnt
< 0 ? cnt
-1 : cnt
))
110 * Move the cursor backward by "n" words. All of the details of motion are
111 * performed by the "backchar" and "forwchar" routines. Error if you try to
112 * move beyond the buffers.
115 backword(int f
, int n
)
118 return (forwword(f
, -n
));
119 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
122 while (inword() == FALSE
) {
123 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
126 while (inword() != FALSE
) {
127 if (backchar_no_header_editor(FALSE
, 1) == FALSE
)
131 return (forwchar(FALSE
, 1));
135 * Move the cursor forward by the specified number of words. All of the motion
136 * is done by "forwchar". Error if you try and move beyond the buffer's end.
139 forwword(int f
, int n
)
142 return (backword(f
, -n
));
145 while (inword() != FALSE
) {
146 if (forwchar(FALSE
, 1) == FALSE
)
150 while (inword() == FALSE
) {
151 if (forwchar(FALSE
, 1) == FALSE
)
155 while (inword() != FALSE
) {
156 if (forwchar(FALSE
, 1) == FALSE
)
167 return((c
&& c
<= 0x7f && isalnum((unsigned char) c
))
168 || (c
>= 0xA0 && !SPECIAL_SPACE(c
)));
174 return((c
&& c
<= 0x7f && isalpha((unsigned char) c
))
175 || (c
>= 0xA0 && !SPECIAL_SPACE(c
)));
181 return((c
< 0xff && isspace((unsigned char) c
)) || SPECIAL_SPACE(c
));
187 return !ucs4_isalnum(c
) && !ucs4_isspace(c
);
192 * Move the cursor forward by the specified number of words. As you move,
193 * convert any characters to upper case. Error if you try and move beyond the
194 * end of the buffer. Bound to "M-U".
197 upperword(int f
, int n
)
203 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
204 return(rdonly()); /* we are in read only mode */
208 while (inword() == FALSE
) {
209 if (forwchar(FALSE
, 1) == FALSE
)
212 while (inword() != FALSE
) {
213 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
214 if (c
>='a' && c
<='z') {
215 ac
.c
= (c
-= 'a'-'A');
216 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
219 if (forwchar(FALSE
, 1) == FALSE
)
227 * Move the cursor forward by the specified number of words. As you move
228 * convert characters to lower case. Error if you try and move over the end of
229 * the buffer. Bound to "M-L".
232 lowerword(int f
, int n
)
238 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
239 return(rdonly()); /* we are in read only mode */
243 while (inword() == FALSE
) {
244 if (forwchar(FALSE
, 1) == FALSE
)
247 while (inword() != FALSE
) {
248 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
249 if (c
>='A' && c
<='Z') {
251 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
254 if (forwchar(FALSE
, 1) == FALSE
)
262 * Move the cursor forward by the specified number of words. As you move
263 * convert the first character of the word to upper case, and subsequent
264 * characters to lower case. Error if you try and move past the end of the
265 * buffer. Bound to "M-C".
268 capword(int f
, int n
)
274 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
275 return(rdonly()); /* we are in read only mode */
279 while (inword() == FALSE
) {
280 if (forwchar(FALSE
, 1) == FALSE
)
283 if (inword() != FALSE
) {
284 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
285 if (c
>='a' && c
<='z') {
286 ac
.c
= (c
-= 'a'-'A');
287 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
290 if (forwchar(FALSE
, 1) == FALSE
)
292 while (inword() != FALSE
) {
293 c
= lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
;
294 if (c
>='A' && c
<='Z') {
295 ac
.c
= (c
+= 'a'-'A');
296 lputc(curwp
->w_dotp
, curwp
->w_doto
, ac
);
299 if (forwchar(FALSE
, 1) == FALSE
)
308 * Kill forward by "n" words. Remember the location of dot. Move forward by
309 * the right number of words. Put dot back where it was and issue the kill
310 * command for the right number of characters. Bound to "M-D".
313 delfword(int f
, int n
)
319 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
320 return(rdonly()); /* we are in read only mode */
323 dotp
= curwp
->w_dotp
;
324 doto
= curwp
->w_doto
;
328 while (inword() != FALSE
) {
329 if (forwchar(FALSE
,1) == FALSE
)
334 while (inword() == FALSE
) {
335 if (forwchar(FALSE
, 1) == FALSE
)
340 while (inword() != FALSE
) {
341 if (forwchar(FALSE
, 1) == FALSE
)
347 curwp
->w_dotp
= dotp
;
348 curwp
->w_doto
= doto
;
349 return (ldelete(size
, kinsert
));
353 * Kill backwards by "n" words. Move backwards by the desired number of words,
354 * counting the characters. When dot is finally moved to its resting place,
355 * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
358 delbword(int f
, int n
)
362 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
363 return(rdonly()); /* we are in read only mode */
366 if (backchar(FALSE
, 1) == FALSE
)
370 while (inword() == FALSE
) {
371 if (backchar(FALSE
, 1) == FALSE
)
375 while (inword() != FALSE
) {
376 if (backchar(FALSE
, 1) == FALSE
)
381 if (forwchar(FALSE
, 1) == FALSE
)
383 return (ldelete(size
, kinsert
));
385 #endif /* MAYBELATER */
388 * Return TRUE if the character at dot is a character that is considered to be
394 if(curwp
->w_doto
< llength(curwp
->w_dotp
))
396 if(ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
))
400 else if(ucs4_ispunct(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
)
401 && !is_user_separator(lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
))
403 if((curwp
->w_doto
> 0) &&
404 ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
- 1).c
) &&
405 (curwp
->w_doto
+ 1 < llength(curwp
->w_dotp
)) &&
406 ucs4_isalnum(lgetc(curwp
->w_dotp
, curwp
->w_doto
+ 1).c
))
418 is_user_separator(UCS c
)
423 for(u
= glo_wordseps
; *u
; u
++)
431 do_quote_match(UCS
*q
, LINE
*l
, UCS
*buf
, size_t buflen
)
437 * The method for determining the quote string is:
438 * 1) strip leading and trailing whitespace from q
439 * 2) add all leading whitespace to buf
441 * 4) if q, append q to buf and any trailing whitespace
442 * 5) repeat steps 3 and 4 as necessary
444 * q in the future could be made to be an array of (UCS *)'s
445 * (">" and whatever the user's quote_string is)
453 /* count leading whitespace as part of the quote */
454 for(j
= 0; j
<= llength(l
) && lgetc(l
, j
).c
== ' ' && j
+1 < buflen
; j
++)
455 buf
[j
] = lgetc(l
, j
).c
;
458 if(q
== NULL
|| *q
== '\0')
461 /* pare down q so it contains no leading or trailing whitespace */
462 for(i
= 0; q
[i
] == ' '; i
++);
464 for(i
= ucs4_strlen(q
); i
> 0 && q
[i
-1] == ' '; i
--);
467 /* for quote strings that are blanks, chop buf to the length of q */
469 if(ucs4_strlen(q
) < buflen
)
470 buf
[ucs4_strlen(q
)] = '\0';
474 while(j
<= llength(l
)){
475 for(i
= qstart
; j
<= llength(l
) && i
< qend
; i
++, j
++)
476 if(q
[i
] != lgetc(l
, j
).c
)
480 if(ucs4_strlen(buf
) + qend
- qstart
< (buflen
- 1))
481 ucs4_strncat(buf
, q
+ qstart
, qend
- qstart
);
485 * if we're this far along, we've matched a quote string,
486 * and should now add the following white space.
488 for(k
= ucs4_strlen(buf
);
489 j
<= llength(l
) && lgetc(l
,j
).c
== ' ' && (k
+ 1 < buflen
);
491 buf
[k
] = lgetc(l
,j
).c
;
501 * Return number of quotes if whatever starts the line matches the quote string
504 quote_match(UCS
*q
, LINE
*gl
, UCS
*bufl
, size_t buflen
)
506 LINE
*nl
= gl
!= curbp
->b_linep
? lforw(gl
) : NULL
;
507 LINE
*pl
= lback(gl
) != curbp
->b_linep
? lback(gl
) : NULL
;
508 UCS bufp
[NSTRING
], bufn
[NSTRING
];
509 int i
, j
, qstart
, qend
;
512 do_quote_match(q
, pl
, bufp
, sizeof(bufp
)); /* previous line */
513 do_quote_match(q
, gl
, bufl
, buflen
); /* given line */
514 do_quote_match(q
, nl
, bufn
, sizeof(bufn
)); /* next line */
516 if(!ucs4_strcmp(bufp
, bufl
) || !ucs4_strcmp(bufl
, bufn
))
517 return ucs4_strlen(bufl
);
519 /* is this line quoted? */
521 /* pare down q so it contains no leading or trailing whitespace */
522 for(i
= 0; q
[i
] == ' '; i
++);
524 for(i
= ucs4_strlen(q
); i
> 0 && q
[i
-1] == ' '; i
--);
526 for(i
= 0; i
< llength(gl
)
528 && lgetc(gl
, i
).c
== q
[i
+qstart
]; i
++);
529 if(i
+ qstart
== qend
)
533 /* compare bufl and bufn */
534 for(i
= 0; bufl
[i
] && bufn
[i
] && bufl
[i
] == bufn
[i
]; i
++);
536 /* go back to last non-space character */
537 for(; i
> 0 && bufl
[i
-1] == ' '; i
--);
539 /* do bufl and bufn differ only in spaces? */
540 for(j
= i
; bufl
[j
] && bufl
[j
] == ' '; j
++);
542 /* if they differ only on trailing spaces, chop bufl to agree with bufn */
544 bufl
[Pmaster
&& quoted_line
? (j
> i
? i
+1 : i
) : i
] = '\0';
546 return ucs4_strlen(bufl
);
550 /* Justify the entire buffer instead of just a paragraph */
552 fillbuf(int f
, int n
)
557 if(curbp
->b_mode
&MDVIEW
){ /* don't allow this command if */
558 return(rdonly()); /* we are in read only mode */
560 else if (fillcol
== 0) { /* no fill column set */
561 mlwrite_utf8("No fill column set", NULL
);
565 if((lastflag
& CFFILL
) && (lastflag
& CFFLBF
)){
566 /* no use doing a full justify twice */
567 thisflag
|= (CFFLBF
| CFFILL
);
571 /* record the pointer of the last line */
572 if(gotoeob(FALSE
, 1) == FALSE
)
575 eobline
= curwp
->w_dotp
; /* last line of buffer */
576 if(!llength(eobline
))
577 eobline
= lback(eobline
);
579 /* and back to the beginning of the buffer */
582 thisflag
|= CFFLBF
; /* CFFILL also gets set in fillpara */
587 curwp
->w_flag
|= WFMODE
;
590 * clear the kill buffer, that's where we'll store undo
591 * information, we can't do the fill buffer because
592 * fillpara relies on its contents
596 getregion(®ion
, eobline
, llength(eobline
));
598 /* Put full message in the kill buffer for undo */
599 if(!ldelete(region
.r_size
, kinsert
))
602 /* before yank'ing, clear lastflag so we don't just unjustify */
603 lastflag
&= ~(CFFLBF
| CFFILL
);
605 /* Now in kill buffer, bring back text to use in fillpara */
610 /* call fillpara until we're at the end of the buffer */
611 while(curwp
->w_dotp
!= curbp
->b_linep
)
612 if(!(fillpara(FALSE
, 1)))
620 * Fill the current paragraph according to the current fill column
623 fillpara(int f
, int n
)
625 UCS
*qstr
, qstr2
[NSTRING
], c
;
630 if(curbp
->b_mode
&MDVIEW
){ /* don't allow this command if */
631 return(rdonly()); /* we are in read only mode */
633 else if (fillcol
== 0) { /* no fill column set */
634 mlwrite_utf8("No fill column set", NULL
);
637 else if(curwp
->w_dotp
== curbp
->b_linep
&& !curwp
->w_markp
) /* don't wrap! */
641 * If there is already a region set, then we may use it
642 * instead of the current paragraph.
647 KEYMENU menu_justify
[12];
650 for(k
= 0; k
< 12; k
++){
651 menu_justify
[k
].name
= NULL
;
652 KS_OSDATASET(&menu_justify
[k
], KS_NONE
);
655 menu_justify
[1].name
= "R";
656 menu_justify
[1].label
= "[" N_("Region") "]";
657 menu_justify
[6].name
= "^C";
658 menu_justify
[6].label
= N_("Cancel");
659 menu_justify
[7].name
= "P";
660 menu_justify
[7].label
= N_("Paragraph");
661 menu_justify
[2].name
= "Q";
662 menu_justify
[2].label
= N_("Quotelevel");
664 wkeyhelp(menu_justify
); /* paint menu */
667 curwp
->w_flag
|= WFMODE
;
669 strncpy(prompt
, "justify Region, Paragraph; or fix Quotelevel ? ", sizeof(prompt
));
670 prompt
[sizeof(prompt
)-1] = '\0';
671 mlwrite_utf8(prompt
, NULL
);
675 switch(c
= GetKey()){
677 case (CTRL
|'C') : /* Bail out! */
679 pputs_utf8(_("ABORT"), 1);
684 case (CTRL
|'M') : /* default */
688 pputs_utf8(_("Region"), 1);
695 pputs_utf8(_("Paragraph"), 1);
702 case '0' : case '1' : case '2' : case '3' : case '4' :
703 case '5' : case '6' : case '7' : case '8' : case '9' :
704 pputs_utf8(_("Quotelevel"), 1);
713 switch(mlreplyd_utf8("Quote Level ? ", num
, sizeof(num
), QNORML
, NULL
)){
716 quotelevel
= atoi(num
);
718 emlwrite("Quote Level cannot be negative", NULL
);
721 else if(quotelevel
> 20){
722 emlwrite("Quote Level should be less than 20", NULL
);
730 emlwrite("Quote Level should be a number", NULL
);
737 emlwrite("Enter the number of quotes you want before the text", NULL
);
742 emlwrite("Quote Level is a number", NULL
);
750 case '0' : case '1' : case '2' : case '3' : case '4' :
751 case '5' : case '6' : case '7' : case '8' : case '9' :
753 quotelevel
= (int) (c
- '0');
761 if(term
.t_mrow
== 0 && km_popped
== 0){
762 movecursor(term
.t_nrow
-2, 0);
766 wkeyhelp(menu_justify
);
767 mlwrite_utf8(prompt
, NULL
);
769 sgarbk
= TRUE
; /* mark menu dirty */
773 /* else fall through */
787 movecursor(term
.t_nrow
, 0);
802 if(action
== 'R' && curwp
->w_markp
){
803 /* let yank() know that it may be restoring a paragraph */
809 curwp
->w_flag
|= WFMODE
;
811 swap_mark_and_dot_if_mark_comes_first();
813 /* determine if we're justifying quoted text or not */
814 qstr
= quote_match(glo_quote_str
,
815 curwp
->w_doto
> 0 ? curwp
->w_dotp
->l_fp
: curwp
->w_dotp
,
817 && *qstr2
? qstr2
: NULL
;
821 * Fillregion moves dot to the end of the filled region.
823 if(!fillregion(qstr
, &addedregion
))
826 set_last_region_added(&addedregion
);
828 else if(action
== 'P'){
831 * Justfiy the current paragraph.
834 if(curwp
->w_markp
) /* clear mark if already set */
837 if(gotoeop(FALSE
, 1) == FALSE
)
840 /* determine if we're justifying quoted text or not */
841 qstr
= quote_match(glo_quote_str
,
842 curwp
->w_dotp
, qstr2
, NSTRING
)
843 && *qstr2
? qstr2
: NULL
;
845 setmark(0,0); /* mark last line of para */
847 /* jump back to the beginning of the paragraph */
850 /* let yank() know that it may be restoring a paragraph */
851 thisflag
|= (CFFILL
| CFFLPA
);
856 curwp
->w_flag
|= WFMODE
;
858 curwp
->w_doto
= 0; /* start region at beginning of line */
861 * Fillregion moves dot to the end of the filled region.
863 if(!fillregion(qstr
, &addedregion
))
866 set_last_region_added(&addedregion
);
868 /* Leave cursor on first char of first line after justified region */
869 curwp
->w_dotp
= lforw(curwp
->w_dotp
);
873 setmark(0,0); /* clear mark */
875 else if(action
== 'Q'){
876 /* let yank() know that it may be restoring a paragraph */
882 curwp
->w_flag
|= WFHARD
;
884 swap_mark_and_dot_if_mark_comes_first();
886 if(!setquotelevelinregion(quotelevel
, &addedregion
))
889 set_last_region_added(&addedregion
);
900 * The region we're filling is the region from dot to mark.
901 * We cut out that region and then put it back in filled.
902 * The cut out part is saved in the ldelete call and the
903 * reinstalled region is noted in addedregion, so that yank()
904 * can delete it and restore the saved part.
907 fillregion(UCS
*qstr
, REGION
*addedregion
)
909 long c
, sz
, last_char
= 0;
910 int i
, j
, qlen
, same_word
,
911 spaces
, word_len
, word_ind
, line_len
, ww
;
912 int starts_midline
= 0;
913 int ends_midline
= 0;
914 int offset_into_start
;
915 LINE
*line_before_start
, *lp
;
916 UCS line_last
, word
[NSTRING
];
919 /* if region starts midline insert a newline */
920 if(curwp
->w_doto
> 0 && curwp
->w_doto
< llength(curwp
->w_dotp
))
923 /* if region ends midline insert a newline at end */
924 if(curwp
->w_marko
> 0 && curwp
->w_marko
< llength(curwp
->w_markp
))
927 /* cut the paragraph into our fill buffer */
929 if(!getregion(®ion
, curwp
->w_markp
, curwp
->w_marko
))
932 if(!ldelete(region
.r_size
, finsert
))
935 line_before_start
= lback(curwp
->w_dotp
);
936 offset_into_start
= curwp
->w_doto
;
941 /* Now insert it back wrapped */
942 spaces
= word_len
= word_ind
= line_len
= same_word
= 0;
943 qlen
= qstr
? ucs4_strlen(qstr
) : 0;
945 /* Beginning with leading quoting... */
949 ww
= wcellwidth(qstr
[i
]);
950 line_len
+= (ww
>= 0 ? ww
: 1);
951 linsert(1, qstr
[i
++]);
954 line_last
= ' '; /* no word-flush space! */
957 /* remove first leading quotes if any */
961 for(i
= qlen
; (c
= fremove(i
)) == ' ' || c
== TAB
; i
++){
962 linsert(1, line_last
= (UCS
) c
);
963 line_len
+= ((c
== TAB
) ? (~line_len
& 0x07) + 1 : 1);
966 /* then digest the rest... */
967 while((c
= fremove(i
++)) >= 0){
971 /* skip next quote string */
973 while(j
< qlen
&& ((c
= fremove(i
+j
)) == qstr
[j
] || c
== ' '))
989 if(spaces
){ /* flush word? */
990 if((line_len
- qlen
> 0)
991 && line_len
+ word_len
+ 1 > fillcol
992 && ((ucs4_isspace(line_last
))
993 || (linsert(1, ' ')))
995 && (line_len
= fpnewline(qstr
)))
996 line_last
= ' '; /* no word-flush space! */
998 if(word_len
){ /* word to write? */
999 if(line_len
&& !ucs4_isspace(line_last
)){
1000 linsert(1, ' '); /* need padding? */
1004 line_len
+= word_len
;
1005 for(j
= 0; j
< word_ind
; j
++)
1006 linsert(1, line_last
= word
[j
]);
1008 if(spaces
> 1 && strchr(".?!:;\")", line_last
)){
1009 linsert(2, line_last
= ' ');
1013 same_word
= word_len
= word_ind
= 0;
1019 if(word_ind
+ 1 >= NSTRING
){
1020 /* Magic! Fake that we output a wrapped word */
1021 if((line_len
- qlen
> 0) && same_word
== 0){
1022 if(!ucs4_isspace(line_last
))
1024 line_len
= fpnewline(qstr
);
1027 line_len
+= word_len
;
1028 for(j
= 0; j
< word_ind
; j
++)
1029 linsert(1, word
[j
]);
1031 word_len
= word_ind
= 0;
1035 word
[word_ind
++] = (UCS
) c
;
1036 ww
= wcellwidth((UCS
) c
);
1037 word_len
+= (ww
>= 0 ? ww
: 1);
1044 if((line_len
- qlen
> 0) && (line_len
+ word_len
+ 1 > fillcol
) && same_word
== 0){
1045 if(!ucs4_isspace(line_last
))
1047 (void) fpnewline(qstr
);
1049 else if(line_len
&& !ucs4_isspace(line_last
))
1052 for(j
= 0; j
< word_ind
; j
++)
1053 linsert(1, word
[j
]);
1056 if(last_char
== '\n')
1060 (void) fpnewline(qstr
);
1063 * Calculate the size of the region that was added.
1065 swapmark(0,1); /* mark current location after adds */
1066 addedregion
->r_linep
= lforw(line_before_start
);
1067 addedregion
->r_offset
= offset_into_start
;
1068 lp
= addedregion
->r_linep
;
1069 sz
= llength(lp
) - addedregion
->r_offset
;
1070 if(lforw(lp
) != curwp
->w_markp
->l_fp
){
1072 while(lp
!= curwp
->w_markp
->l_fp
){
1073 sz
+= llength(lp
) + 1;
1078 sz
-= llength(curwp
->w_markp
) - curwp
->w_marko
;
1079 addedregion
->r_size
= sz
;
1085 * We want to back up to the end of the original
1086 * region instead of being here after the added newline.
1099 * fpnewline - output a fill paragraph newline mindful of quote string
1102 fpnewline(UCS
*quote
)
1107 for(len
= 0; quote
&& *quote
; quote
++){
1110 ww
= wcellwidth(*quote
);
1111 len
+= (ww
>= 0 ? ww
: 1);
1120 setquotelevelinregion(int quotelevel
, REGION
*addedregion
)
1122 int i
, standards_based
= 0;
1123 int quote_chars
= 0, backuptoprevline
= 0;
1124 int starts_midline
= 0, ends_midline
= 0, offset_into_start
;
1126 UCS qstr_def1
[] = { '>', ' ', 0}, qstr_def2
[] = { '>', 0};
1127 LINE
*lp
, *line_before_start
;
1130 if(curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
1131 return(rdonly()); /* we are in read only mode */
1134 || !ucs4_strcmp(glo_quote_str
, qstr_def1
)
1135 || !ucs4_strcmp(glo_quote_str
, qstr_def2
))
1138 if(!standards_based
){
1139 emlwrite("Quote level setting only works with standard \"> \" quotes", NULL
);
1143 /* if region starts midline insert a newline */
1144 if(curwp
->w_doto
> 0 && curwp
->w_doto
< llength(curwp
->w_dotp
))
1147 /* if region ends midline insert a newline at end */
1148 if(curwp
->w_marko
> 0 && curwp
->w_marko
< llength(curwp
->w_markp
)){
1151 /* count quote chars for re-insertion */
1152 for(i
= 0; i
< llength(curwp
->w_markp
); ++i
)
1153 if(lgetc(curwp
->w_markp
, i
).c
!= '>')
1158 else if(curwp
->w_marko
== 0)
1161 /* find the size of the region */
1162 getregion(®ion
, curwp
->w_markp
, curwp
->w_marko
);
1164 /* cut the paragraph into our fill buffer */
1166 if(!ldelete(region
.r_size
, finsert
))
1169 line_before_start
= lback(curwp
->w_dotp
);
1170 offset_into_start
= curwp
->w_doto
;
1172 /* if region starts midline add a newline */
1177 while(fremove(i
) >= 0){
1179 /* remove all quote strs from current line */
1180 if(standards_based
){
1181 while((c
= fremove(i
)) == '>')
1190 /* insert quotelevel quote strs */
1191 if(standards_based
){
1192 linsert(quotelevel
, '>');
1199 /* put back the actual line */
1200 while((c
= fremove(i
++)) >= 0 && c
!= '\n')
1201 linsert(1, (UCS
) c
);
1207 /* if region ends midline add a newline */
1211 linsert(quote_chars
, '>');
1212 if(curwp
->w_doto
< llength(curwp
->w_dotp
)
1213 && lgetc(curwp
->w_dotp
, curwp
->w_doto
).c
!= ' ')
1219 * Calculate the size of the region that was added.
1221 swapmark(0,1); /* mark current location after adds */
1222 addedregion
->r_linep
= lforw(line_before_start
);
1223 addedregion
->r_offset
= offset_into_start
;
1224 lp
= addedregion
->r_linep
;
1225 sz
= llength(lp
) - addedregion
->r_offset
;
1226 if(lforw(lp
) != curwp
->w_markp
->l_fp
){
1228 while(lp
!= curwp
->w_markp
->l_fp
){
1229 sz
+= llength(lp
) + 1;
1234 sz
-= llength(curwp
->w_markp
) - curwp
->w_marko
;
1235 addedregion
->r_size
= sz
;
1240 * This puts us at the end of the quoted region instead
1241 * of on the following line. This makes it convenient
1242 * for the user to follow a quotelevel adjustment with
1243 * a Justify if desired.
1245 if(backuptoprevline
){
1250 if(ends_midline
){ /* doesn't need fixing otherwise */