2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
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: Random routines
18 * This file contains the command processing functions for a number of random
19 * commands. There is no functional grouping here, for sure.
24 #include "osdep/terminal.h"
28 int tabsize
; /* Tab size (0: use real tabs) */
32 * Display the current position of the cursor, in origin 1 X-Y coordinates,
33 * the character that is under the cursor (in octal), and the fraction of the
34 * text that is before the cursor. The displayed column is not the current
35 * column, but the column that would be used on an infinite width display.
36 * Normally this is bound to "C-X =".
39 showcpos(int f
, int n
)
46 register int thisline
= 0;
49 clp
= lforw(curbp
->b_linep
); /* Grovel the data. */
54 if (clp
==curwp
->w_dotp
&& cbo
==curwp
->w_doto
) {
58 if (cbo
== llength(clp
)) {
59 if (clp
== curbp
->b_linep
)
69 snprintf(buffer
,sizeof(buffer
),"line %d of %d (%d%%%%), character %ld of %ld (%d%%%%)",
70 thisline
+1, lines
+1, (int)((100L*(thisline
+1))/(lines
+1)),
71 nbc
, nch
, (nch
) ? (int)((100L*nbc
)/nch
) : 0);
73 emlwrite(buffer
, NULL
);
79 * Return current column. Stop at first non-blank given TRUE argument.
88 for (i
=0; i
<curwp
->w_doto
; ++i
) {
89 c
= lgetc(curwp
->w_dotp
, i
).c
;
90 if (c
!=' ' && c
!='\t' && bflg
)
97 else if (ISCONTROL(c
)){
104 col
+= (ww
>= 0 ? ww
: 1);
114 * Set tab size if given non-default argument (n <> 1). Otherwise, insert a
115 * tab into file. If given argument, n, of zero, change to true tabs.
116 * If n > 1, simulate tab stop every n-characters using spaces. This has to be
117 * done in this slightly funny way because the tab (in ASCII) has been turned
118 * into "C-I" (in 10 bit code) already. Bound to "C-I".
126 if (n
== 0 || n
> 1) {
132 return(linsert(1, '\t'));
134 return(linsert(tabsize
- (getccol(FALSE
) % tabsize
), ' '));
139 * Insert a newline. Bound to "C-M".
142 newline(int f
, int n
)
146 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
147 return(rdonly()); /* we are in read only mode */
152 if(TERM_OPTIMIZE
&& (curwp
->w_dotp
!= curwp
->w_bufp
->b_linep
)){
156 if(curwp
->w_doto
!= 0)
158 scrolldown(curwp
, l
, n
);
162 /* if we are in C mode and this is a default <NL> */
163 /* pico's never in C mode */
165 if(Pmaster
&& Pmaster
->allow_flowed_text
&& curwp
->w_doto
166 && ucs4_isspace(lgetc(curwp
->w_dotp
, curwp
->w_doto
- 1).c
)
167 && !(curwp
->w_doto
== 3
168 && lgetc(curwp
->w_dotp
, 0).c
== '-'
169 && lgetc(curwp
->w_dotp
, 1).c
== '-'
170 && lgetc(curwp
->w_dotp
, 2).c
== ' ')){
172 * flowed mode, make the newline a hard one by
173 * stripping trailing space.
176 for(i
= curwp
->w_doto
- 1;
177 i
&& ucs4_isspace(lgetc(curwp
->w_dotp
, i
- 1).c
);
179 dellen
= curwp
->w_doto
- i
;
181 ldelete(dellen
, NULL
);
183 /* insert some lines */
185 if ((s
=lnewline()) != TRUE
)
194 * Delete forward. This is real easy, because the basic delete routine does
195 * all of the work. Watches for negative arguments, and does the right thing.
196 * If any argument is present, it kills rather than deletes, to prevent loss
197 * of text if typed with a big argument. Normally bound to "C-D".
200 forwdel(int f
, int n
)
202 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
203 return(rdonly()); /* we are in read only mode */
206 return (backdel(f
, -n
));
208 if(TERM_OPTIMIZE
&& (curwp
->w_dotp
!= curwp
->w_bufp
->b_linep
)){
211 if(worthit(&l
) && curwp
->w_doto
== llength(curwp
->w_dotp
))
212 scrollup(curwp
, l
+1, 1);
215 if (f
!= FALSE
) { /* Really a kill. */
216 if ((lastflag
&CFKILL
) == 0)
221 return (ldelete((long) n
, f
? kinsert
: NULL
));
227 * Delete backwards. This is quite easy too, because it's all done with other
228 * functions. Just move the cursor back, and delete forwards. Like delete
229 * forward, this actually does a kill if presented with an argument. Bound to
230 * both "RUBOUT" and "C-H".
233 backdel(int f
, int n
)
237 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
238 return(rdonly()); /* we are in read only mode */
241 return (forwdel(f
, -n
));
243 if(TERM_OPTIMIZE
&& curwp
->w_dotp
!= curwp
->w_bufp
->b_linep
){
246 if(worthit(&l
) && curwp
->w_doto
== 0 &&
247 lback(curwp
->w_dotp
) != curwp
->w_bufp
->b_linep
){
248 if(l
== curwp
->w_toprow
)
249 scrollup(curwp
, l
+1, 1);
250 else if(llength(lback(curwp
->w_dotp
)) == 0)
251 scrollup(curwp
, l
-1, 1);
253 scrollup(curwp
, l
, 1);
257 if (f
!= FALSE
) { /* Really a kill. */
258 if ((lastflag
&CFKILL
) == 0)
264 if ((s
=backchar(f
, n
)) == TRUE
)
265 s
= ldelete((long) n
, f
? kinsert
: NULL
);
273 * killtext - delete the line that the cursor is currently in.
274 * a greatly pared down version of its former self.
277 killtext(int f
, int n
)
282 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
283 return(rdonly()); /* we are in read only mode */
285 if ((lastflag
&CFKILL
) == 0) /* Clear kill buffer if */
286 kdelete(); /* last wasn't a kill. */
288 if(gmode
& MDDTKILL
){ /* */
289 if((chunk
= llength(curwp
->w_dotp
) - curwp
->w_doto
) == 0){
296 gotobol(FALSE
, 1); /* wack from bol past newline */
297 chunk
= llength(curwp
->w_dotp
) + 1;
302 /* optimize what motion we can */
303 if(opt_scroll
&& (curwp
->w_dotp
!= curwp
->w_bufp
->b_linep
)){
307 scrollup(curwp
, l
, 1);
311 return(ldelete((long) chunk
, kinsert
));
316 * Yank text back from the kill buffer. This is really easy. All of the work
317 * is done by the standard insert routines. All you do is run the loop, and
318 * check for errors. Bound to "C-Y".
324 REGION region
, *added_region
;
327 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
328 return(rdonly()); /* we are in read only mode */
333 if(TERM_OPTIMIZE
&& (curwp
->w_dotp
!= curwp
->w_bufp
->b_linep
)){
336 if(worthit(&l
) && !(lastflag
&CFFILL
)){
341 while((ch
=fremove(i
++)) >= 0)
344 if(t
+l
< curwp
->w_toprow
+curwp
->w_ntrows
)
345 scrolldown(curwp
, l
, t
);
349 if(lastflag
& CFFILL
){ /* if last command was fillpara() */
350 if(lastflag
& CFFLBF
){
352 dotp
= curwp
->w_dotp
;
355 getregion(®ion
, dotp
, llength(dotp
));
358 added_region
= get_last_region_added();
360 curwp
->w_dotp
= added_region
->r_linep
;
361 curwp
->w_doto
= added_region
->r_offset
;
362 region
= (*added_region
);
368 if(!ldelete(region
.r_size
, NULL
))
370 } /* then splat out the saved buffer */
374 while ((c
= ((lastflag
&CFFILL
)
375 ? ((lastflag
& CFFLBF
) ? kremove(i
) : fremove(i
))
376 : kremove(i
))) >= 0) {
378 if (lnewline() == FALSE
)
381 if (linsert(1, c
) == FALSE
)
389 if(lastflag
&CFFLPA
){ /* if last command was fill paragraph */
390 curwp
->w_dotp
= lforw(curwp
->w_dotp
);
393 curwp
->w_flag
|= WFMODE
;
407 * worthit - generic sort of test to roughly gage usefulness of using
408 * optimized scrolling.
411 * returns the line on the screen, l, that the dot is currently on
416 int i
; /* l is current line */
417 unsigned below
; /* below is avg # of ch/line under . */
419 *l
= doton(&i
, &below
);
420 below
= (i
> 0) ? below
/(unsigned)i
: 0;