blob: 92582609fa99756e159e40c95b5825be8ae33cfb [file] [log] [blame]
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * move.c -- This file is part of GNU nano. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +00003 * *
Chris Allegretta8a07a962009-12-02 03:36:22 +00004 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
Benno Schulenberg7a9f4a42014-04-30 20:18:26 +00005 * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. *
Benno Schulenberg406e5242016-08-29 15:14:18 +02006 * Copyright (C) 2014, 2015, 2016 Benno Schulenberg *
7 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02008 * GNU nano is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published *
10 * by the Free Software Foundation, either version 3 of the License, *
11 * or (at your option) any later version. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000012 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020013 * GNU nano is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty *
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
16 * See the GNU General Public License for more details. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000017 * *
18 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020019 * along with this program. If not, see http://www.gnu.org/licenses/. *
Chris Allegrettabceb1b22000-06-19 04:22:15 +000020 * *
21 **************************************************************************/
22
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000023#include "proto.h"
Chris Allegretta6efda542001-04-28 18:03:52 +000024
Chris Allegrettabceb1b22000-06-19 04:22:15 +000025#include <string.h>
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +000026#include <ctype.h>
Chris Allegretta4da1fc62000-06-21 03:00:43 +000027
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000028/* Move to the first line of the file. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +000029void do_first_line(void)
David Lawrence Ramsey4be15f02004-05-23 21:33:23 +000030{
Benno Schulenberg925ad632016-10-12 21:07:16 +020031 openfile->current = openfile->fileage;
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +000032 openfile->current_x = 0;
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +000033 openfile->placewewant = 0;
34
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +020035 refresh_needed = TRUE;
David Lawrence Ramsey4be15f02004-05-23 21:33:23 +000036}
37
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000038/* Move to the last line of the file. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +000039void do_last_line(void)
David Lawrence Ramsey4be15f02004-05-23 21:33:23 +000040{
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +000041 openfile->current = openfile->filebot;
David Lawrence Ramsey46f56652005-11-05 17:50:06 +000042 openfile->current_x = strlen(openfile->filebot->data);
43 openfile->placewewant = xplustabs();
Benno Schulenberg925ad632016-10-12 21:07:16 +020044
45 /* Set the last line of the screen as the target for the cursor. */
David Lawrence Ramseya9b862c2005-08-16 01:27:05 +000046 openfile->current_y = editwinrows - 1;
Benno Schulenberg58c3dd62017-01-09 15:21:15 +010047 ensure_line_is_visible();
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +000048
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +020049 refresh_needed = TRUE;
Benno Schulenberg318ed6b2016-04-12 10:24:57 +020050 focusing = FALSE;
David Lawrence Ramsey4be15f02004-05-23 21:33:23 +000051}
52
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000053/* Move up one page. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +000054void do_page_up(void)
Chris Allegretta1e57e682000-07-03 04:24:39 +000055{
Benno Schulenbergbd1c5d72016-08-21 15:49:39 +020056 int i, mustmove, skipped = 0;
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000057
Benno Schulenberg17ab9a22015-07-26 17:04:29 +000058 /* If the cursor is less than a page away from the top of the file,
59 * put it at the beginning of the first line. */
Benno Schulenberga4044a72016-12-09 13:31:04 +010060 if (openfile->current->lineno == 1 || (!ISSET(SOFTWRAP) &&
Benno Schulenberg00b293b2016-08-21 15:39:00 +020061 openfile->current->lineno <= editwinrows - 2)) {
David Lawrence Ramsey4d464372005-07-16 22:50:30 +000062 do_first_line();
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000063 return;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +000064 }
Chris Allegretta1e57e682000-07-03 04:24:39 +000065
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000066 /* If we're not in smooth scrolling mode, put the cursor at the
67 * beginning of the top line of the edit window, as Pico does. */
Benno Schulenberga4044a72016-12-09 13:31:04 +010068 if (!ISSET(SMOOTH_SCROLL)) {
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000069 openfile->current = openfile->edittop;
Chris Allegretta08273aa2010-03-21 04:56:37 +000070 openfile->placewewant = openfile->current_y = 0;
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000071 }
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000072
Benno Schulenbergbd1c5d72016-08-21 15:49:39 +020073 mustmove = (editwinrows < 3) ? 1 : editwinrows - 2;
74
75 for (i = mustmove; i - skipped > 0 && openfile->current != openfile->fileage; i--) {
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000076 openfile->current = openfile->current->prev;
Benno Schulenbergf80dcb22014-06-21 19:01:51 +000077#ifndef NANO_TINY
Chris Allegrettac9199e92009-11-26 18:23:00 +000078 if (ISSET(SOFTWRAP) && openfile->current) {
David Lawrence Ramsey62634162016-12-07 12:33:25 -060079 skipped += strlenpt(openfile->current->data) / editwincols;
Chris Allegrettac9199e92009-11-26 18:23:00 +000080#ifdef DEBUG
Benno Schulenberga4044a72016-12-09 13:31:04 +010081 fprintf(stderr, "paging up: i = %d, skipped = %d based on line %ld len %lu\n",
Benno Schulenbergf80dcb22014-06-21 19:01:51 +000082 i, skipped, (long)openfile->current->lineno, (unsigned long)strlenpt(openfile->current->data));
Chris Allegrettac9199e92009-11-26 18:23:00 +000083#endif
84 }
Benno Schulenbergf80dcb22014-06-21 19:01:51 +000085#endif
Chris Allegrettae2df2c82009-11-24 17:15:53 +000086 }
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000087
88 openfile->current_x = actual_x(openfile->current->data,
Benno Schulenberg2fae87d2016-05-27 21:22:56 +020089 openfile->placewewant);
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +000090
91 /* Scroll the edit window up a page. */
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +020092 adjust_viewport(STATIONARY);
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +020093 refresh_needed = TRUE;
Chris Allegretta1e57e682000-07-03 04:24:39 +000094}
95
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000096/* Move down one page. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +000097void do_page_down(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +000098{
Benno Schulenbergbd1c5d72016-08-21 15:49:39 +020099 int i, mustmove;
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000100
Benno Schulenberg17ab9a22015-07-26 17:04:29 +0000101 /* If the cursor is less than a page away from the bottom of the file,
102 * put it at the end of the last line. */
Benno Schulenberg0208ae72017-01-12 17:33:46 +0100103 if (openfile->current->lineno + maxlines - 2 >= openfile->filebot->lineno) {
David Lawrence Ramsey4d464372005-07-16 22:50:30 +0000104 do_last_line();
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000105 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000106 }
107
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000108 /* If we're not in smooth scrolling mode, put the cursor at the
109 * beginning of the top line of the edit window, as Pico does. */
Benno Schulenberga4044a72016-12-09 13:31:04 +0100110 if (!ISSET(SMOOTH_SCROLL)) {
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000111 openfile->current = openfile->edittop;
Chris Allegretta08273aa2010-03-21 04:56:37 +0000112 openfile->placewewant = openfile->current_y = 0;
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000113 }
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000114
Benno Schulenberg0208ae72017-01-12 17:33:46 +0100115 mustmove = (maxlines < 3) ? 1 : maxlines - 2;
Benno Schulenbergbd1c5d72016-08-21 15:49:39 +0200116
117 for (i = mustmove; i > 0 && openfile->current != openfile->filebot; i--) {
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000118 openfile->current = openfile->current->next;
Chris Allegretta8c1edd12009-11-16 04:28:40 +0000119#ifdef DEBUG
Benno Schulenberga4044a72016-12-09 13:31:04 +0100120 fprintf(stderr, "paging down: moving to line %lu\n", (unsigned long)openfile->current->lineno);
Chris Allegretta8c1edd12009-11-16 04:28:40 +0000121#endif
122
123 }
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000124
125 openfile->current_x = actual_x(openfile->current->data,
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200126 openfile->placewewant);
David Lawrence Ramsey5e146e82005-07-17 00:01:18 +0000127
128 /* Scroll the edit window down a page. */
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +0200129 adjust_viewport(STATIONARY);
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200130 refresh_needed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000131}
132
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000133#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey036a9d52005-11-10 05:26:37 +0000134/* Move up to the beginning of the last beginning-of-paragraph line
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000135 * before the current line. If allow_update is TRUE, update the screen
136 * afterwards. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000137void do_para_begin(bool allow_update)
138{
Benno Schulenberg70130392016-10-12 21:10:04 +0200139 filestruct *was_current = openfile->current;
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000140
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000141 if (openfile->current != openfile->fileage) {
David Lawrence Ramseyb1c20622016-12-22 13:01:27 -0600142 do
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000143 openfile->current = openfile->current->prev;
David Lawrence Ramseyb1c20622016-12-22 13:01:27 -0600144 while (!begpar(openfile->current));
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000145 }
146
David Lawrence Ramsey31d7b362005-11-09 04:20:55 +0000147 openfile->current_x = 0;
David Lawrence Ramsey31d7b362005-11-09 04:20:55 +0000148
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000149 if (allow_update)
Benno Schulenberg70130392016-10-12 21:10:04 +0200150 edit_redraw(was_current);
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000151}
152
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000153/* Move up to the beginning of the last beginning-of-paragraph line
154 * before the current line, and update the screen afterwards. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000155void do_para_begin_void(void)
156{
157 do_para_begin(TRUE);
158}
159
David Lawrence Ramsey036a9d52005-11-10 05:26:37 +0000160/* Move down to the beginning of the last line of the current paragraph.
161 * Then move down one line farther if there is such a line, or to the
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000162 * end of the current line if not. If allow_update is TRUE, update the
163 * screen afterwards. A line is the last line of a paragraph if it is
164 * in a paragraph, and the next line either is the beginning line of a
165 * paragraph or isn't in a paragraph. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000166void do_para_end(bool allow_update)
167{
Benno Schulenberg70130392016-10-12 21:10:04 +0200168 filestruct *was_current = openfile->current;
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000169
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000170 while (openfile->current != openfile->filebot &&
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200171 !inpar(openfile->current))
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000172 openfile->current = openfile->current->next;
173
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000174 while (openfile->current != openfile->filebot &&
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200175 inpar(openfile->current->next) &&
176 !begpar(openfile->current->next)) {
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000177 openfile->current = openfile->current->next;
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000178 }
179
David Lawrence Ramsey31d7b362005-11-09 04:20:55 +0000180 if (openfile->current != openfile->filebot) {
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000181 openfile->current = openfile->current->next;
David Lawrence Ramsey31d7b362005-11-09 04:20:55 +0000182 openfile->current_x = 0;
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +0200183 } else
David Lawrence Ramsey31d7b362005-11-09 04:20:55 +0000184 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000185
186 if (allow_update)
Benno Schulenberg70130392016-10-12 21:10:04 +0200187 edit_redraw(was_current);
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000188}
189
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000190/* Move down to the beginning of the last line of the current paragraph.
191 * Then move down one line farther if there is such a line, or to the
192 * end of the current line if not, and update the screen afterwards. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000193void do_para_end_void(void)
194{
195 do_para_end(TRUE);
196}
197#endif /* !DISABLE_JUSTIFY */
198
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200199/* Move to the preceding block of text in the file. */
200void do_prev_block(void)
201{
202 filestruct *was_current = openfile->current;
203 bool is_text = FALSE, seen_text = FALSE;
204
205 /* Skip backward until first blank line after some nonblank line(s). */
206 while (openfile->current->prev != NULL && (!seen_text || is_text)) {
207 openfile->current = openfile->current->prev;
208 is_text = !white_string(openfile->current->data);
209 seen_text = seen_text || is_text;
210 }
211
212 /* Step forward one line again if this one is blank. */
213 if (openfile->current->next != NULL &&
214 white_string(openfile->current->data))
215 openfile->current = openfile->current->next;
216
217 openfile->current_x = 0;
218 edit_redraw(was_current);
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200219}
220
221/* Move to the next block of text in the file. */
222void do_next_block(void)
223{
224 filestruct *was_current = openfile->current;
225 bool is_white = white_string(openfile->current->data);
226 bool seen_white = is_white;
227
228 /* Skip forward until first nonblank line after some blank line(s). */
229 while (openfile->current->next != NULL && (!seen_white || is_white)) {
230 openfile->current = openfile->current->next;
231 is_white = white_string(openfile->current->data);
232 seen_white = seen_white || is_white;
233 }
234
235 openfile->current_x = 0;
236 edit_redraw(was_current);
Benno Schulenbergc6dbcf92016-06-25 15:16:52 +0200237}
238
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000239/* Move to the previous word in the file. If allow_punct is TRUE, treat
240 * punctuation as part of a word. If allow_update is TRUE, update the
Benno Schulenberg6620de02015-09-05 09:22:50 +0000241 * screen afterwards. */
242void do_prev_word(bool allow_punct, bool allow_update)
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000243{
Benno Schulenberg70130392016-10-12 21:10:04 +0200244 filestruct *was_current = openfile->current;
Benno Schulenbergb4103322015-09-05 09:40:09 +0000245 bool seen_a_word = FALSE, step_forward = FALSE;
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000246
247 assert(openfile->current != NULL && openfile->current->data != NULL);
248
Benno Schulenbergb4103322015-09-05 09:40:09 +0000249 /* Move backward until we pass over the start of a word. */
250 while (TRUE) {
251 /* If at the head of a line, move to the end of the preceding one. */
252 if (openfile->current_x == 0) {
253 if (openfile->current->prev == NULL)
254 break;
255 openfile->current = openfile->current->prev;
256 openfile->current_x = strlen(openfile->current->data);
257 }
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000258
Benno Schulenbergb4103322015-09-05 09:40:09 +0000259 /* Step back one character. */
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000260 openfile->current_x = move_mbleft(openfile->current->data,
Benno Schulenbergb4103322015-09-05 09:40:09 +0000261 openfile->current_x);
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000262
Benno Schulenbergb4103322015-09-05 09:40:09 +0000263 if (is_word_mbchar(openfile->current->data + openfile->current_x,
264 allow_punct)) {
265 seen_a_word = TRUE;
266 /* If at the head of a line now, this surely is a word start. */
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000267 if (openfile->current_x == 0)
Benno Schulenbergb4103322015-09-05 09:40:09 +0000268 break;
269 } else if (seen_a_word) {
270 /* This is space now: we've overshot the start of the word. */
271 step_forward = TRUE;
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000272 break;
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000273 }
274 }
275
Benno Schulenbergb4103322015-09-05 09:40:09 +0000276 if (step_forward)
277 /* Move one character forward again to sit on the start of the word. */
278 openfile->current_x = move_mbright(openfile->current->data,
279 openfile->current_x);
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000280
281 /* If allow_update is TRUE, update the screen. */
Benno Schulenberg318ed6b2016-04-12 10:24:57 +0200282 if (allow_update) {
283 focusing = FALSE;
Benno Schulenberg70130392016-10-12 21:10:04 +0200284 edit_redraw(was_current);
Benno Schulenberg318ed6b2016-04-12 10:24:57 +0200285 }
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000286}
287
Benno Schulenbergc1151662016-02-22 12:49:08 +0000288/* Move to the previous word in the file, treating punctuation as part of a
289 * word if the WORD_BOUNDS flag is set, and update the screen afterwards. */
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000290void do_prev_word_void(void)
291{
David Lawrence Ramsey4f03daf2005-08-10 22:12:28 +0000292 do_prev_word(ISSET(WORD_BOUNDS), TRUE);
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000293}
Benno Schulenbergc1151662016-02-22 12:49:08 +0000294
295/* Move to the next word in the file. If allow_punct is TRUE, treat
296 * punctuation as part of a word. If allow_update is TRUE, update the
297 * screen afterwards. Return TRUE if we started on a word, and FALSE
298 * otherwise. */
299bool do_next_word(bool allow_punct, bool allow_update)
300{
Benno Schulenberg70130392016-10-12 21:10:04 +0200301 filestruct *was_current = openfile->current;
Benno Schulenbergc1151662016-02-22 12:49:08 +0000302 bool started_on_word = is_word_mbchar(openfile->current->data +
303 openfile->current_x, allow_punct);
304 bool seen_space = !started_on_word;
305
306 assert(openfile->current != NULL && openfile->current->data != NULL);
307
308 /* Move forward until we reach the start of a word. */
309 while (TRUE) {
310 /* If at the end of a line, move to the beginning of the next one. */
311 if (openfile->current->data[openfile->current_x] == '\0') {
312 /* If at the end of the file, stop. */
313 if (openfile->current->next == NULL)
314 break;
315 openfile->current = openfile->current->next;
316 openfile->current_x = 0;
317 seen_space = TRUE;
318 } else {
319 /* Step forward one character. */
320 openfile->current_x = move_mbright(openfile->current->data,
321 openfile->current_x);
322 }
323
324 /* If this is not a word character, then it's a separator; else
325 * if we've already seen a separator, then it's a word start. */
326 if (!is_word_mbchar(openfile->current->data + openfile->current_x,
327 allow_punct))
328 seen_space = TRUE;
329 else if (seen_space)
330 break;
331 }
332
Benno Schulenbergc1151662016-02-22 12:49:08 +0000333 /* If allow_update is TRUE, update the screen. */
Benno Schulenberg318ed6b2016-04-12 10:24:57 +0200334 if (allow_update) {
335 focusing = FALSE;
Benno Schulenberg70130392016-10-12 21:10:04 +0200336 edit_redraw(was_current);
Benno Schulenberg318ed6b2016-04-12 10:24:57 +0200337 }
Benno Schulenbergc1151662016-02-22 12:49:08 +0000338
339 /* Return whether we started on a word. */
340 return started_on_word;
341}
342
343/* Move to the next word in the file, treating punctuation as part of a word
344 * if the WORD_BOUNDS flag is set, and update the screen afterwards. */
345void do_next_word_void(void)
346{
347 do_next_word(ISSET(WORD_BOUNDS), TRUE);
348}
David Lawrence Ramseyc4037f32005-07-20 21:31:19 +0000349
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200350/* Make sure that the current line, when it is partially scrolled off the
351 * screen in softwrap mode, is scrolled fully into view. */
352void ensure_line_is_visible(void)
353{
354#ifndef NANO_TINY
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100355 if (ISSET(SOFTWRAP) && strlenpt(openfile->current->data) / editwincols +
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200356 openfile->current_y >= editwinrows) {
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +0200357 adjust_viewport(ISSET(SMOOTH_SCROLL) ? FLOWING : CENTERING);
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200358 refresh_needed = TRUE;
359 }
360#endif
361}
362
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000363/* Move to the beginning of the current line. If the SMART_HOME flag is
364 * set, move to the first non-whitespace character of the current line
David Lawrence Ramsey9ea05902006-04-24 19:44:04 +0000365 * if we aren't already there, or to the beginning of the current line
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000366 * if we are. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000367void do_home(void)
368{
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200369 size_t was_column = xplustabs();
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000370
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000371#ifndef NANO_TINY
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000372 if (ISSET(SMART_HOME)) {
373 size_t current_x_save = openfile->current_x;
374
375 openfile->current_x = indent_length(openfile->current->data);
376
377 if (openfile->current_x == current_x_save ||
378 openfile->current->data[openfile->current_x] == '\0')
379 openfile->current_x = 0;
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200380 } else
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000381#endif
382 openfile->current_x = 0;
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200383
384 openfile->placewewant = xplustabs();
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000385
Benno Schulenberg2f664762016-07-26 19:47:00 +0200386 if (need_horizontal_scroll(was_column, openfile->placewewant))
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000387 update_line(openfile->current, openfile->current_x);
388}
389
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000390/* Move to the end of the current line. */
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000391void do_end(void)
392{
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200393 size_t was_column = xplustabs();
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000394
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000395 openfile->current_x = strlen(openfile->current->data);
396 openfile->placewewant = xplustabs();
397
Benno Schulenberg2f664762016-07-26 19:47:00 +0200398 if (need_horizontal_scroll(was_column, openfile->placewewant))
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000399 update_line(openfile->current, openfile->current_x);
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200400
401 ensure_line_is_visible();
David Lawrence Ramseyca62f9f2005-07-20 19:24:11 +0000402}
403
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000404/* If scroll_only is FALSE, move up one line. If scroll_only is TRUE,
405 * scroll up one line without scrolling the cursor. */
Benno Schulenberg0a3a6442016-07-25 17:23:45 +0200406void do_up(bool scroll_only)
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000407{
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200408 size_t was_column = xplustabs();
409
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000410 /* If we're at the top of the file, or if scroll_only is TRUE and
411 * the top of the file is onscreen, get out. */
Benno Schulenberga4044a72016-12-09 13:31:04 +0100412 if (openfile->current == openfile->fileage ||
413 (scroll_only && openfile->edittop == openfile->fileage))
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000414 return;
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000415
Chris Allegrettabce7d402009-09-03 23:29:14 +0000416 assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno);
David Lawrence Ramseyb199cae2005-03-09 20:35:10 +0000417
David Lawrence Ramsey8f4762a2005-07-16 22:35:11 +0000418 /* Move the current line of the edit window up. */
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000419 openfile->current = openfile->current->prev;
420 openfile->current_x = actual_x(openfile->current->data,
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200421 openfile->placewewant);
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000422
Benno Schulenberg4c476bc2016-10-28 11:37:03 +0200423 /* When the cursor was on the first line of the edit window (or when just
424 * scrolling without moving the cursor), scroll the edit window up -- one
425 * line if we're in smooth scrolling mode, and half a page otherwise. */
426 if (openfile->current->next == openfile->edittop || scroll_only)
Benno Schulenberg5416b9c2016-10-24 13:56:00 +0200427 edit_scroll(UPWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ?
428 1 : editwinrows / 2 + 1);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000429
Benno Schulenberg03b168d2016-07-26 20:06:10 +0200430 /* If the lines weren't already redrawn, see if they need to be. */
431 if (openfile->current_y > 0) {
432 /* Redraw the prior line if it was horizontally scrolled. */
433 if (need_horizontal_scroll(was_column, 0))
434 update_line(openfile->current->next, 0);
435 /* Redraw the current line if it needs to be horizontally scrolled. */
436 if (need_horizontal_scroll(0, xplustabs()))
437 update_line(openfile->current, openfile->current_x);
438 }
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000439}
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000440
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000441/* Move up one line. */
442void do_up_void(void)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000443{
Benno Schulenberg0a3a6442016-07-25 17:23:45 +0200444 do_up(FALSE);
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000445}
446
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000447/* If scroll_only is FALSE, move down one line. If scroll_only is TRUE,
448 * scroll down one line without scrolling the cursor. */
Benno Schulenberg0a3a6442016-07-25 17:23:45 +0200449void do_down(bool scroll_only)
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000450{
Benno Schulenberg54a11052014-03-03 13:24:09 +0000451#ifndef NANO_TINY
Benno Schulenberg3278f832014-03-05 09:47:35 +0000452 int amount = 0, enough;
Benno Schulenbergb1a7fdd2014-03-03 10:02:13 +0000453 filestruct *topline;
Benno Schulenberg54a11052014-03-03 13:24:09 +0000454#endif
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200455 size_t was_column = xplustabs();
Chris Allegretta139934a2009-08-30 03:50:16 +0000456
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000457 /* If we're at the bottom of the file, get out. */
Benno Schulenberg58346382015-12-08 18:54:13 +0000458 if (openfile->current == openfile->filebot)
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000459 return;
460
Benno Schulenberg58346382015-12-08 18:54:13 +0000461 assert(ISSET(SOFTWRAP) || openfile->current_y ==
462 openfile->current->lineno - openfile->edittop->lineno);
463 assert(openfile->current->next != NULL);
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000464
Benno Schulenberg54a11052014-03-03 13:24:09 +0000465#ifndef NANO_TINY
Chris Allegretta139934a2009-08-30 03:50:16 +0000466 if (ISSET(SOFTWRAP)) {
Benno Schulenberg2d50c4f2016-04-15 14:39:54 +0200467 /* Compute the number of lines to scroll. */
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100468 amount = strlenpt(openfile->current->data) / editwincols -
469 xplustabs() / editwincols +
470 strlenpt(openfile->current->next->data) / editwincols +
Benno Schulenberg2d50c4f2016-04-15 14:39:54 +0200471 openfile->current_y - editwinrows + 2;
Benno Schulenbergb1a7fdd2014-03-03 10:02:13 +0000472 topline = openfile->edittop;
473 /* Reduce the amount when there are overlong lines at the top. */
474 for (enough = 1; enough < amount; enough++) {
Faissal Bensefiade95ca62016-10-20 09:44:29 +0100475 amount -= strlenpt(topline->data) / editwincols;
Benno Schulenberg97f6ae52016-09-14 12:40:58 +0200476 if (amount > 0)
477 topline = topline->next;
478 if (amount < enough) {
Benno Schulenbergb1a7fdd2014-03-03 10:02:13 +0000479 amount = enough;
480 break;
481 }
Benno Schulenbergb1a7fdd2014-03-03 10:02:13 +0000482 }
Chris Allegretta139934a2009-08-30 03:50:16 +0000483 }
Benno Schulenberg54a11052014-03-03 13:24:09 +0000484#endif
Chris Allegretta139934a2009-08-30 03:50:16 +0000485
Benno Schulenberg2d50c4f2016-04-15 14:39:54 +0200486 /* Move to the next line in the file. */
487 openfile->current = openfile->current->next;
488 openfile->current_x = actual_x(openfile->current->data,
489 openfile->placewewant);
490
David Lawrence Ramseyf2ac2012016-12-28 09:43:23 -0600491 /* When the cursor was on the last line of the edit window (or when just
492 * scrolling without moving the cursor), scroll the edit window down -- one
493 * line if we're in smooth scrolling mode, and half a page otherwise. */
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000494#ifndef NANO_TINY
Benno Schulenberg77a1a5c2016-09-13 22:06:11 +0200495 if (openfile->current_y == editwinrows - 1 || amount > 0 || scroll_only) {
Benno Schulenberg54a11052014-03-03 13:24:09 +0000496 if (amount < 1 || scroll_only)
497 amount = 1;
Benno Schulenberg77a1a5c2016-09-13 22:06:11 +0200498
499 edit_scroll(DOWNWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ?
500 amount : editwinrows / 2 + 1);
Benno Schulenberg503654e2016-04-12 14:00:36 +0200501
502 if (ISSET(SOFTWRAP)) {
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200503 refresh_needed = TRUE;
Benno Schulenberg503654e2016-04-12 14:00:36 +0200504 return;
505 }
Benno Schulenberg8476bf82016-10-15 18:05:01 +0200506 }
Benno Schulenberg77a1a5c2016-09-13 22:06:11 +0200507#else
508 if (openfile->current_y == editwinrows - 1)
509 edit_scroll(DOWNWARD, editwinrows / 2 + 1);
510#endif
Benno Schulenberge393a6c2016-04-12 13:29:51 +0200511
Benno Schulenberg03b168d2016-07-26 20:06:10 +0200512 /* If the lines weren't already redrawn, see if they need to be. */
513 if (openfile->current_y < editwinrows - 1) {
514 /* Redraw the prior line if it was horizontally scrolled. */
515 if (need_horizontal_scroll(was_column, 0))
516 update_line(openfile->current->prev, 0);
517 /* Redraw the current line if it needs to be horizontally scrolled. */
518 if (need_horizontal_scroll(0, xplustabs()))
519 update_line(openfile->current, openfile->current_x);
520 }
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000521}
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000522
523/* Move down one line. */
524void do_down_void(void)
525{
Benno Schulenberg0a3a6442016-07-25 17:23:45 +0200526 do_down(FALSE);
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000527}
528
529#ifndef NANO_TINY
Benno Schulenberg0a3a6442016-07-25 17:23:45 +0200530/* Scroll up one line without scrolling the cursor. */
531void do_scroll_up(void)
532{
533 do_up(TRUE);
534}
535
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000536/* Scroll down one line without scrolling the cursor. */
537void do_scroll_down(void)
538{
539 do_down(TRUE);
540}
541#endif
David Lawrence Ramsey2de84c12005-10-24 02:12:09 +0000542
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000543/* Move left one character. */
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000544void do_left(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000545{
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200546 size_t was_column = xplustabs();
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000547
548 if (openfile->current_x > 0)
549 openfile->current_x = move_mbleft(openfile->current->data,
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200550 openfile->current_x);
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000551 else if (openfile->current != openfile->fileage) {
David Lawrence Ramsey2c36e2e2006-07-06 22:17:47 +0000552 do_up_void();
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000553 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000554 }
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +0000555
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000556 openfile->placewewant = xplustabs();
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +0000557
Benno Schulenberg2f664762016-07-26 19:47:00 +0200558 if (need_horizontal_scroll(was_column, openfile->placewewant))
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000559 update_line(openfile->current, openfile->current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000560}
561
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000562/* Move right one character. */
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000563void do_right(void)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000564{
Benno Schulenbergc9e99642016-07-26 11:47:53 +0200565 size_t was_column = xplustabs();
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +0000566
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000567 assert(openfile->current_x <= strlen(openfile->current->data));
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000568
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000569 if (openfile->current->data[openfile->current_x] != '\0')
570 openfile->current_x = move_mbright(openfile->current->data,
Benno Schulenberg2fae87d2016-05-27 21:22:56 +0200571 openfile->current_x);
Benno Schulenbergd66ea082016-10-18 11:46:15 +0200572 else if (openfile->current != openfile->filebot) {
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000573 openfile->current_x = 0;
Benno Schulenbergd66ea082016-10-18 11:46:15 +0200574#ifndef NANO_TINY
575 if (ISSET(SOFTWRAP))
David Lawrence Ramsey62634162016-12-07 12:33:25 -0600576 openfile->current_y -= strlenpt(openfile->current->data) / editwincols;
Benno Schulenbergd66ea082016-10-18 11:46:15 +0200577#endif
578 }
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +0000579
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000580 openfile->placewewant = xplustabs();
David Lawrence Ramseyf00c9612005-07-14 18:01:08 +0000581
Benno Schulenberg2f664762016-07-26 19:47:00 +0200582 if (need_horizontal_scroll(was_column, openfile->placewewant))
David Lawrence Ramsey6ad59cd2005-07-08 20:09:16 +0000583 update_line(openfile->current, openfile->current_x);
Benno Schulenberg80416272016-09-20 12:53:12 +0200584
585 if (openfile->current_x == 0)
586 do_down_void();
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200587 else
588 ensure_line_is_visible();
Chris Allegrettabceb1b22000-06-19 04:22:15 +0000589}