blob: b13e1224227925e9cbeea8abf1cccc2cc19c69f5 [file] [log] [blame]
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001/**************************************************************************
Benno Schulenberg514cd9a2016-08-29 17:10:49 +02002 * text.c -- This file is part of GNU nano. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +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 Mark Majeres *
7 * Copyright (C) 2016 Mike Scalora *
8 * Copyright (C) 2015, 2016 Benno Schulenberg *
Benno Schulenberg7531b712016-12-07 20:37:36 +01009 * Copyright (C) 2016 Sumedh Pendurkar *
Benno Schulenberg406e5242016-08-29 15:14:18 +020010 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020011 * GNU nano is free software: you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published *
13 * by the Free Software Foundation, either version 3 of the License, *
14 * or (at your option) any later version. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000015 * *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020016 * GNU nano is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty *
18 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
19 * See the GNU General Public License for more details. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000020 * *
21 * You should have received a copy of the GNU General Public License *
Benno Schulenberg514cd9a2016-08-29 17:10:49 +020022 * along with this program. If not, see http://www.gnu.org/licenses/. *
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000023 * *
24 **************************************************************************/
25
David Lawrence Ramsey034b9942005-12-08 02:47:10 +000026#include "proto.h"
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000027
David Lawrence Ramseyee11c6a2005-11-02 19:42:02 +000028#include <stdio.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000029#include <signal.h>
30#include <unistd.h>
31#include <string.h>
32#include <fcntl.h>
33#include <sys/wait.h>
34#include <errno.h>
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000035
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000036#ifndef NANO_TINY
David Lawrence Ramsey8779a172005-11-08 16:45:22 +000037static pid_t pid = -1;
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000038 /* The PID of the forked process in execute_command(), for use
39 * with the cancel_command() signal handler. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000040#endif
41#ifndef DISABLE_WRAPPING
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +000042static bool prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000043 /* Should we prepend wrapped text to the next line? */
44#endif
45#ifndef DISABLE_JUSTIFY
Benno Schulenberg3264d0c2016-10-12 19:59:26 +020046static filestruct *jusbuffer = NULL;
47 /* The buffer where we store unjustified text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000048static filestruct *jusbottom = NULL;
Benno Schulenberg3264d0c2016-10-12 19:59:26 +020049 /* A pointer to the end of the buffer with unjustified text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +000050#endif
51
Benno Schulenberg68a03142016-12-07 13:10:40 +010052#ifdef ENABLE_WORDCOMPLETION
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +053053static int pletion_x = 0;
54 /* The x position in pletion_line of the last found completion. */
55static completion_word *list_of_completions;
56 /* A linked list of the completions that have been attepmted. */
57#endif
58
59#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +000060/* Toggle the mark. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000061void do_mark(void)
62{
63 openfile->mark_set = !openfile->mark_set;
Benno Schulenberg382c9d72016-04-24 11:28:28 +020064
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000065 if (openfile->mark_set) {
66 statusbar(_("Mark Set"));
67 openfile->mark_begin = openfile->current;
68 openfile->mark_begin_x = openfile->current_x;
Benno Schulenberg382c9d72016-04-24 11:28:28 +020069 openfile->kind_of_mark = HARDMARK;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000070 } else {
David Lawrence Ramsey7b0531a2006-07-31 01:30:31 +000071 statusbar(_("Mark Unset"));
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000072 openfile->mark_begin = NULL;
73 openfile->mark_begin_x = 0;
Benno Schulenbergf920e0d2016-12-03 17:00:28 +010074 refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000075 }
76}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +000077#endif /* !NANO_TINY */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000078
Benno Schulenbergf2259912015-04-17 09:24:17 +000079#if !defined(DISABLE_COLOR) || !defined(DISABLE_SPELLER)
80/* Return an error message containing the given name. */
81char *invocation_error(const char *name)
82{
83 char *message, *invoke_error = _("Error invoking \"%s\"");
84
85 message = charalloc(strlen(invoke_error) + strlen(name) + 1);
86 sprintf(message, invoke_error, name);
87 return message;
88}
Benno Schulenberg953ccc92015-06-28 14:12:25 +000089#endif
Benno Schulenbergf2259912015-04-17 09:24:17 +000090
David Lawrence Ramseyf1982f02006-12-10 17:57:09 +000091/* Delete the character under the cursor. */
Benno Schulenberg64896ba2014-06-08 19:02:12 +000092void do_deletion(undo_type action)
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000093{
Benno Schulenberg1102aaa2014-06-09 20:26:54 +000094#ifndef NANO_TINY
David Lawrence Ramsey83ff6442017-01-19 19:58:37 -060095 size_t orig_rows = 0;
Benno Schulenberg1102aaa2014-06-09 20:26:54 +000096#endif
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +000097
Benno Schulenberg953ccc92015-06-28 14:12:25 +000098 assert(openfile->current != NULL && openfile->current->data != NULL &&
99 openfile->current_x <= strlen(openfile->current->data));
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000100
101 openfile->placewewant = xplustabs();
102
103 if (openfile->current->data[openfile->current_x] != '\0') {
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200104 /* We're in the middle of a line: delete the current character. */
Benno Schulenberg79a4bf82016-12-19 19:58:15 +0100105 int char_len = parse_mbchar(openfile->current->data +
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200106 openfile->current_x, NULL, NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000107 size_t line_len = strlen(openfile->current->data +
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200108 openfile->current_x);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000109
110 assert(openfile->current_x < strlen(openfile->current->data));
111
Benno Schulenbergff36b052014-05-29 18:50:13 +0000112#ifndef NANO_TINY
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000113 update_undo(action);
Benno Schulenberg1102aaa2014-06-09 20:26:54 +0000114
Chris Allegrettaa8bc4922009-12-12 22:21:20 +0000115 if (ISSET(SOFTWRAP))
David Lawrence Ramsey83ff6442017-01-19 19:58:37 -0600116 orig_rows = strlenpt(openfile->current->data) / editwincols;
Benno Schulenberg1102aaa2014-06-09 20:26:54 +0000117#endif
Chris Allegrettaa8bc4922009-12-12 22:21:20 +0000118
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200119 /* Move the remainder of the line "in", over the current character. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000120 charmove(&openfile->current->data[openfile->current_x],
Benno Schulenberg79a4bf82016-12-19 19:58:15 +0100121 &openfile->current->data[openfile->current_x + char_len],
122 line_len - char_len + 1);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000123 null_at(&openfile->current->data, openfile->current_x +
Benno Schulenberg79a4bf82016-12-19 19:58:15 +0100124 line_len - char_len);
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200125
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000126#ifndef NANO_TINY
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200127 /* Adjust the mark if it is after the cursor on the current line. */
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000128 if (openfile->mark_set && openfile->mark_begin == openfile->current &&
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200129 openfile->mark_begin_x > openfile->current_x)
Benno Schulenberg79a4bf82016-12-19 19:58:15 +0100130 openfile->mark_begin_x -= char_len;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000131#endif
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200132 /* Adjust the file size. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000133 openfile->totsize--;
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +0000134 } else if (openfile->current != openfile->filebot) {
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200135 /* We're at the end of a line and not at the end of the file: join
136 * this line with the next. */
137 filestruct *joining = openfile->current->next;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000138
139 assert(openfile->current_x == strlen(openfile->current->data));
140
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200141 /* If there is a magic line, and we're before it: don't eat it. */
142 if (joining == openfile->filebot && openfile->current_x != 0 &&
143 !ISSET(NO_NEWLINES)) {
Benno Schulenbergfc7825d2015-07-06 19:08:13 +0000144#ifndef NANO_TINY
145 if (action == BACK)
146 add_undo(BACK);
147#endif
Benno Schulenberg8f5fa242015-07-06 18:48:15 +0000148 return;
Benno Schulenbergfc7825d2015-07-06 19:08:13 +0000149 }
Benno Schulenberg8f5fa242015-07-06 18:48:15 +0000150
Benno Schulenbergff36b052014-05-29 18:50:13 +0000151#ifndef NANO_TINY
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000152 add_undo(action);
Benno Schulenbergff36b052014-05-29 18:50:13 +0000153#endif
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200154 /* Add the contents of the next line to those of the current one. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000155 openfile->current->data = charealloc(openfile->current->data,
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200156 strlen(openfile->current->data) + strlen(joining->data) + 1);
157 strcat(openfile->current->data, joining->data);
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +0000158
Benno Schulenberg5f4d7592016-06-06 19:57:51 +0200159 /* Adjust the file size. */
160 openfile->totsize--;
Benno Schulenbergedf230b2016-06-04 11:35:11 +0200161
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000162#ifndef NANO_TINY
Benno Schulenberg5f4d7592016-06-06 19:57:51 +0200163 /* Remember the new file size for a possible redo. */
164 openfile->current_undo->newsize = openfile->totsize;
165
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200166 /* Adjust the mark if it was on the line that was "eaten". */
167 if (openfile->mark_set && openfile->mark_begin == joining) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000168 openfile->mark_begin = openfile->current;
169 openfile->mark_begin_x += openfile->current_x;
170 }
171#endif
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200172 unlink_node(joining);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000173 renumber(openfile->current);
Benno Schulenberg57f52a82015-06-20 09:42:26 +0000174
Benno Schulenberg296ff1e2015-06-28 14:04:03 +0000175 /* Two lines were joined, so we need to refresh the screen. */
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200176 refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000177 } else
Benno Schulenbergf0c65bc2016-06-06 20:29:53 +0200178 /* We're at the end-of-file: nothing to do. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000179 return;
180
Benno Schulenberg1102aaa2014-06-09 20:26:54 +0000181#ifndef NANO_TINY
Benno Schulenberg43f35fc2016-10-18 13:03:01 +0200182 ensure_line_is_visible();
183
Benno Schulenberg7598b772016-11-12 15:57:42 +0100184 /* If the number of screen rows that a softwrapped line occupies
185 * has changed, we need a full refresh. */
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200186 if (ISSET(SOFTWRAP) && refresh_needed == FALSE)
David Lawrence Ramsey83ff6442017-01-19 19:58:37 -0600187 if ((strlenpt(openfile->current->data) / editwincols) != orig_rows)
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200188 refresh_needed = TRUE;
Benno Schulenberg1102aaa2014-06-09 20:26:54 +0000189#endif
Chris Allegrettaa8bc4922009-12-12 22:21:20 +0000190
David Lawrence Ramsey0f6236f2005-11-09 00:08:29 +0000191 set_modified();
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000192}
193
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000194/* Delete the character under the cursor. */
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000195void do_delete(void)
196{
197 do_deletion(DEL);
198}
199
David Lawrence Ramsey5b7b3e32005-12-31 21:22:54 +0000200/* Backspace over one character. That is, move the cursor left one
David Lawrence Ramsey84d22e32006-11-08 13:05:50 +0000201 * character, and then delete the character under the cursor. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000202void do_backspace(void)
203{
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000204 if (openfile->current != openfile->fileage || openfile->current_x > 0) {
David Lawrence Ramsey1c3bfa92005-09-13 04:53:44 +0000205 do_left();
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000206 do_deletion(BACK);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000207 }
208}
209
Benno Schulenbergb3e40512015-07-31 11:52:26 +0000210#ifndef NANO_TINY
211/* Delete text from the cursor until the first start of a word to
212 * the right, or to the left when backward is true. */
213void do_cutword(bool backward)
214{
215 /* Remember the current cursor position. */
216 filestruct *is_current = openfile->current;
217 size_t is_current_x = openfile->current_x;
218
Benno Schulenberge2b65722016-03-20 11:10:31 +0000219 /* Remember where the cutbuffer is and then make it seem blank. */
220 filestruct *is_cutbuffer = cutbuffer;
221 filestruct *is_cutbottom = cutbottom;
222 cutbuffer = NULL;
223 cutbottom = NULL;
224
Benno Schulenbergb3e40512015-07-31 11:52:26 +0000225 /* Move the cursor to a word start, to the left or to the right. */
226 if (backward)
227 do_prev_word(ISSET(WORD_BOUNDS), FALSE);
228 else
229 do_next_word(ISSET(WORD_BOUNDS), FALSE);
230
231 /* Set the mark at the start of that word. */
232 openfile->mark_begin = openfile->current;
233 openfile->mark_begin_x = openfile->current_x;
234 openfile->mark_set = TRUE;
235
236 /* Put the cursor back where it was, so an undo will put it there too. */
237 openfile->current = is_current;
238 openfile->current_x = is_current_x;
239
240 /* Now kill the marked region and a word is gone. */
241 do_cut_text_void();
Benno Schulenberge2b65722016-03-20 11:10:31 +0000242
243 /* Discard the cut word and restore the cutbuffer. */
244 free_filestruct(cutbuffer);
245 cutbuffer = is_cutbuffer;
246 cutbottom = is_cutbottom;
Benno Schulenbergb3e40512015-07-31 11:52:26 +0000247}
248
249/* Delete a word leftward. */
250void do_cut_prev_word(void)
251{
Benno Schulenberg17cf8332016-05-30 09:09:36 +0200252 do_cutword(TRUE);
Benno Schulenbergb3e40512015-07-31 11:52:26 +0000253}
254
255/* Delete a word rightward. */
256void do_cut_next_word(void)
257{
Benno Schulenberg17cf8332016-05-30 09:09:36 +0200258 do_cutword(FALSE);
Benno Schulenbergb3e40512015-07-31 11:52:26 +0000259}
260#endif /* !NANO_TINY */
261
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +0000262/* Insert a tab. If the TABS_TO_SPACES flag is set, insert the number
263 * of spaces that a tab would normally take up. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000264void do_tab(void)
265{
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000266#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000267 if (ISSET(TABS_TO_SPACES)) {
Benno Schulenberg68acc1d2016-06-24 10:17:06 +0200268 char *spaces = charalloc(tabsize + 1);
269 size_t length = tabsize - (xplustabs() % tabsize);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000270
Benno Schulenberg68acc1d2016-06-24 10:17:06 +0200271 charset(spaces, ' ', length);
272 spaces[length] = '\0';
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000273
Benno Schulenberg68acc1d2016-06-24 10:17:06 +0200274 do_output(spaces, length, TRUE);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000275
Benno Schulenberg68acc1d2016-06-24 10:17:06 +0200276 free(spaces);
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000277 } else
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000278#endif
Benno Schulenberg68acc1d2016-06-24 10:17:06 +0200279 do_output((char *)"\t", 1, TRUE);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000280}
281
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000282#ifndef NANO_TINY
David Lawrence Ramseye44cd2d2007-01-11 22:54:55 +0000283/* Indent or unindent the current line (or, if the mark is on, all lines
284 * covered by the mark) len columns, depending on whether len is
285 * positive or negative. If the TABS_TO_SPACES flag is set, indent or
286 * unindent by len spaces. Otherwise, indent or unindent by (len /
287 * tabsize) tabs and (len % tabsize) spaces. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000288void do_indent(ssize_t cols)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000289{
290 bool indent_changed = FALSE;
291 /* Whether any indenting or unindenting was done. */
292 bool unindent = FALSE;
293 /* Whether we're unindenting text. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000294 char *line_indent = NULL;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000295 /* The text added to each line in order to indent it. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000296 size_t line_indent_len = 0;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000297 /* The length of the text added to each line in order to indent
298 * it. */
299 filestruct *top, *bot, *f;
300 size_t top_x, bot_x;
301
302 assert(openfile->current != NULL && openfile->current->data != NULL);
303
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000304 /* If cols is zero, get out. */
305 if (cols == 0)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000306 return;
307
Benno Schulenberg189fff42014-04-04 20:45:28 +0000308 /* If cols is negative, make it positive and set unindent to TRUE. */
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000309 if (cols < 0) {
310 cols = -cols;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000311 unindent = TRUE;
312 /* Otherwise, we're indenting, in which case the file will always be
313 * modified, so set indent_changed to TRUE. */
314 } else
315 indent_changed = TRUE;
316
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000317 /* If the mark is on, use all lines covered by the mark. */
318 if (openfile->mark_set)
319 mark_order((const filestruct **)&top, &top_x,
Benno Schulenberg95f417f2016-06-14 11:06:04 +0200320 (const filestruct **)&bot, &bot_x, NULL);
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000321 /* Otherwise, use the current line. */
322 else {
323 top = openfile->current;
324 bot = top;
325 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000326
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000327 if (!unindent) {
328 /* Set up the text we'll be using as indentation. */
329 line_indent = charalloc(cols + 1);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000330
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000331 if (ISSET(TABS_TO_SPACES)) {
332 /* Set the indentation to cols spaces. */
333 charset(line_indent, ' ', cols);
334 line_indent_len = cols;
335 } else {
336 /* Set the indentation to (cols / tabsize) tabs and (cols %
337 * tabsize) spaces. */
338 size_t num_tabs = cols / tabsize;
339 size_t num_spaces = cols % tabsize;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000340
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000341 charset(line_indent, '\t', num_tabs);
342 charset(line_indent + num_tabs, ' ', num_spaces);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000343
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000344 line_indent_len = num_tabs + num_spaces;
345 }
346
347 line_indent[line_indent_len] = '\0';
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000348 }
349
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000350 /* Go through each line of the text. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000351 for (f = top; f != bot->next; f = f->next) {
352 size_t line_len = strlen(f->data);
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000353 size_t indent_len = indent_length(f->data);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000354
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000355 if (!unindent) {
356 /* If we're indenting, add the characters in line_indent to
357 * the beginning of the non-whitespace text of this line. */
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000358 f->data = charealloc(f->data, line_len + line_indent_len + 1);
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000359 charmove(&f->data[indent_len + line_indent_len],
360 &f->data[indent_len], line_len - indent_len + 1);
361 strncpy(f->data + indent_len, line_indent, line_indent_len);
362 openfile->totsize += line_indent_len;
363
364 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000365 if (openfile->mark_set && f == openfile->mark_begin &&
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000366 openfile->mark_begin_x >= indent_len)
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000367 openfile->mark_begin_x += line_indent_len;
368
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000369 if (f == openfile->current && openfile->current_x >= indent_len)
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000370 openfile->current_x += line_indent_len;
371
372 /* If the NO_NEWLINES flag isn't set, and this is the
373 * magicline, add a new magicline. */
374 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
375 new_magicline();
376 } else {
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000377 size_t indent_col = strnlenpt(f->data, indent_len);
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000378 /* The length in columns of the indentation on this line. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000379
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000380 if (cols <= indent_col) {
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000381 size_t indent_new = actual_x(f->data, indent_col - cols);
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000382 /* The length of the indentation remaining on
383 * this line after we unindent. */
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000384 size_t indent_shift = indent_len - indent_new;
David Lawrence Ramsey5bb77272006-05-06 14:37:33 +0000385 /* The change in the indentation on this line
386 * after we unindent. */
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000387
David Lawrence Ramseyaf9052d2006-05-01 17:14:25 +0000388 /* If we're unindenting, and there's at least cols
David Lawrence Ramsey2ca3fc92006-05-01 16:48:12 +0000389 * columns' worth of indentation at the beginning of the
390 * non-whitespace text of this line, remove it. */
391 charmove(&f->data[indent_new], &f->data[indent_len],
392 line_len - indent_shift - indent_new + 1);
393 null_at(&f->data, line_len - indent_shift + 1);
394 openfile->totsize -= indent_shift;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000395
David Lawrence Ramsey2e8fac62006-04-29 15:44:58 +0000396 /* Keep track of the change in the current line. */
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000397 if (openfile->mark_set && f == openfile->mark_begin &&
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000398 openfile->mark_begin_x > indent_new) {
399 if (openfile->mark_begin_x <= indent_len)
400 openfile->mark_begin_x = indent_new;
401 else
402 openfile->mark_begin_x -= indent_shift;
403 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000404
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000405 if (f == openfile->current &&
406 openfile->current_x > indent_new) {
David Lawrence Ramseyeb4f90e2006-05-05 14:22:42 +0000407 if (openfile->current_x <= indent_len)
408 openfile->current_x = indent_new;
409 else
410 openfile->current_x -= indent_shift;
411 }
David Lawrence Ramsey7194a612006-04-29 16:11:21 +0000412
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000413 /* We've unindented, so the indentation changed. */
414 indent_changed = TRUE;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000415 }
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000416 }
417 }
418
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000419 if (!unindent)
David Lawrence Ramsey25456862006-05-05 15:43:52 +0000420 /* Clean up. */
David Lawrence Ramsey80669c32006-05-05 15:41:43 +0000421 free(line_indent);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000422
423 if (indent_changed) {
Benno Schulenberg4bc8ff12015-12-03 09:17:06 +0000424 /* Throw away the undo stack, to prevent making mistakes when
425 * the user tries to undo something in the reindented text. */
Benno Schulenbergf8459382016-01-15 16:44:50 +0000426 discard_until(NULL, openfile);
Benno Schulenberg4bc8ff12015-12-03 09:17:06 +0000427
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000428 /* Mark the file as modified. */
429 set_modified();
430
431 /* Update the screen. */
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +0200432 refresh_needed = TRUE;
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000433 }
434}
435
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000436/* Indent the current line, or all lines covered by the mark if the mark
437 * is on, tabsize columns. */
438void do_indent_void(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000439{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000440 do_indent(tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000441}
442
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000443/* Unindent the current line, or all lines covered by the mark if the
444 * mark is on, tabsize columns. */
445void do_unindent(void)
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000446{
David Lawrence Ramseyaee00d42006-07-05 18:42:22 +0000447 do_indent(-tabsize);
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000448}
Mike Scalora6a2032f2016-05-25 22:13:50 +0200449#endif /* !NANO_TINY */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000450
Mike Scalora6a2032f2016-05-25 22:13:50 +0200451/* Test whether the string is empty or consists of only blanks. */
452bool white_string(const char *s)
453{
454 while (*s != '\0' && (is_blank_mbchar(s) || *s == '\r'))
455 s += move_mbright(s, 0);
456
457 return !*s;
458}
459
Benno Schulenberg08cd1972016-09-08 21:00:51 +0200460#ifdef ENABLE_COMMENT
Mike Scalora6a2032f2016-05-25 22:13:50 +0200461/* Comment or uncomment the current line or the marked lines. */
462void do_comment()
463{
464 const char *comment_seq = "#";
465 undo_type action = UNCOMMENT;
466 filestruct *top, *bot, *f;
Benno Schulenberg9192b7f2016-06-01 09:36:05 +0200467 size_t top_x, bot_x;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200468 bool empty, all_empty = TRUE;
469
Mike Scalora6a2032f2016-05-25 22:13:50 +0200470 assert(openfile->current != NULL && openfile->current->data != NULL);
471
472#ifndef DISABLE_COLOR
473 if (openfile->syntax && openfile->syntax->comment)
474 comment_seq = openfile->syntax->comment;
475
476 /* Does the syntax not allow comments? */
477 if (strlen(comment_seq) == 0) {
478 statusbar(_("Commenting is not supported for this file type"));
479 return;
480 }
481#endif
482
483 /* Determine which lines to work on. */
484 if (openfile->mark_set)
Benno Schulenberg95f417f2016-06-14 11:06:04 +0200485 mark_order((const filestruct **)&top, &top_x,
486 (const filestruct **)&bot, &bot_x, NULL);
Mike Scalora6a2032f2016-05-25 22:13:50 +0200487 else {
488 top = openfile->current;
489 bot = top;
490 }
491
Benno Schulenberg9192b7f2016-06-01 09:36:05 +0200492 /* If only the magic line is selected, don't do anything. */
493 if (top == bot && bot == openfile->filebot && !ISSET(NO_NEWLINES)) {
494 statusbar(_("Cannot comment past end of file"));
495 return;
496 }
Mike Scalora6a2032f2016-05-25 22:13:50 +0200497
498 /* Figure out whether to comment or uncomment the selected line or lines. */
499 for (f = top; f != bot->next; f = f->next) {
500 empty = white_string(f->data);
501
502 /* If this line is not blank and not commented, we comment all. */
503 if (!empty && !comment_line(PREFLIGHT, f, comment_seq)) {
504 action = COMMENT;
505 break;
506 }
507 all_empty = all_empty && empty;
508 }
509
510 /* If all selected lines are blank, we comment them. */
511 action = all_empty ? COMMENT : action;
512
Benno Schulenberg9192b7f2016-06-01 09:36:05 +0200513 add_undo(action);
514
515 /* Store the comment sequence used for the operation, because it could
516 * change when the file name changes; we need to know what it was. */
517 openfile->current_undo->strdata = mallocstrcpy(NULL, comment_seq);
518
Mike Scalora6a2032f2016-05-25 22:13:50 +0200519 /* Process the selected line or lines. */
520 for (f = top; f != bot->next; f = f->next) {
Benno Schulenberg9192b7f2016-06-01 09:36:05 +0200521 /* Comment/uncomment a line, and add undo data when line changed. */
522 if (comment_line(action, f, comment_seq))
Mike Scalora6a2032f2016-05-25 22:13:50 +0200523 update_comment_undo(f->lineno);
Mike Scalora6a2032f2016-05-25 22:13:50 +0200524 }
525
Benno Schulenberg9192b7f2016-06-01 09:36:05 +0200526 set_modified();
527 refresh_needed = TRUE;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200528}
529
530/* Test whether the given line can be uncommented, or add or remove a comment,
531 * depending on action. Return TRUE if the line is uncommentable, or when
532 * anything was added or removed; FALSE otherwise. */
533bool comment_line(undo_type action, filestruct *f, const char *comment_seq)
534{
535 size_t comment_seq_len = strlen(comment_seq);
536 const char *post_seq = strchr(comment_seq, '|');
537 /* The postfix, if this is a bracketing type comment sequence. */
538 size_t pre_len = post_seq ? post_seq++ - comment_seq : comment_seq_len;
539 /* Length of prefix. */
540 size_t post_len = post_seq ? comment_seq_len - pre_len - 1 : 0;
541 /* Length of postfix. */
542 size_t line_len = strlen(f->data);
543
544 if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
545 return FALSE;
546
547 if (action == COMMENT) {
548 /* Make room for the comment sequence(s), move the text right and
549 * copy them in. */
550 f->data = charealloc(f->data, line_len + pre_len + post_len + 1);
551 charmove(&f->data[pre_len], f->data, line_len);
552 charmove(f->data, comment_seq, pre_len);
553 if (post_len)
554 charmove(&f->data[pre_len + line_len], post_seq, post_len);
555 f->data[pre_len + line_len + post_len] = '\0';
556
557 openfile->totsize += pre_len + post_len;
558
559 /* If needed, adjust the position of the mark and of the cursor. */
560 if (openfile->mark_set && f == openfile->mark_begin)
561 openfile->mark_begin_x += pre_len;
562 if (f == openfile->current) {
563 openfile->current_x += pre_len;
564 openfile->placewewant = xplustabs();
565 }
566
567 return TRUE;
568 }
569
570 /* If the line is commented, report it as uncommentable, or uncomment it. */
571 if (strncmp(f->data, comment_seq, pre_len) == 0 && (post_len == 0 ||
572 strcmp(&f->data[line_len - post_len], post_seq) == 0)) {
573
574 if (action == PREFLIGHT)
575 return TRUE;
576
577 /* Erase the comment prefix by moving the non-comment part. */
578 charmove(f->data, &f->data[pre_len], line_len - pre_len);
579 /* Truncate the postfix if there was one. */
580 f->data[line_len - pre_len - post_len] = '\0';
581
582 openfile->totsize -= pre_len + post_len;
583
584 /* If needed, adjust the position of the mark and then the cursor. */
585 if (openfile->mark_set && f == openfile->mark_begin) {
586 if (openfile->mark_begin_x < pre_len)
587 openfile->mark_begin_x = 0;
588 else
589 openfile->mark_begin_x -= pre_len;
590 }
591 if (f == openfile->current) {
592 if (openfile->current_x < pre_len)
593 openfile->current_x = 0;
594 else
595 openfile->current_x -= pre_len;
596 openfile->placewewant = xplustabs();
597 }
598
599 return TRUE;
600 }
601
602 return FALSE;
603}
604
605/* Perform an undo or redo for a comment or uncomment action. */
606void handle_comment_action(undo *u, bool undoing, bool add_comment)
607{
608 undo_group *group = u->grouping;
609
610 /* When redoing, reposition the cursor and let the commenter adjust it. */
611 if (!undoing)
612 goto_line_posx(u->lineno, u->begin);
613
614 while (group) {
615 filestruct *f = fsfromline(group->top_line);
616
617 while (f && f->lineno <= group->bottom_line) {
618 comment_line(undoing ^ add_comment ?
619 COMMENT : UNCOMMENT, f, u->strdata);
620 f = f->next;
621 }
622 group = group->next;
623 }
624
625 /* When undoing, reposition the cursor to the recorded location. */
626 if (undoing)
627 goto_line_posx(u->lineno, u->begin);
628
629 refresh_needed = TRUE;
630}
631#endif /* ENABLE_COMMENT */
632
633#ifndef NANO_TINY
Benno Schulenberg60815462014-05-15 20:00:46 +0000634#define redo_paste undo_cut
635#define undo_paste redo_cut
636
Benno Schulenberg189fff42014-04-04 20:45:28 +0000637/* Undo a cut, or redo an uncut. */
Chris Allegrettab549f372008-09-16 21:35:19 +0000638void undo_cut(undo *u)
639{
Benno Schulenberg189fff42014-04-04 20:45:28 +0000640 /* If we cut the magicline, we may as well not crash. :/ */
Chris Allegretta42726f72009-07-27 04:16:44 +0000641 if (!u->cutbuffer)
642 return;
Chris Allegrettab549f372008-09-16 21:35:19 +0000643
Benno Schulenberg189fff42014-04-04 20:45:28 +0000644 /* Get to where we need to uncut from. */
Benno Schulenbergf0bb5032015-06-27 09:27:19 +0000645 if (u->xflags == WAS_WHOLE_LINE)
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +0000646 goto_line_posx(u->mark_begin_lineno, 0);
647 else
648 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
Chris Allegretta42726f72009-07-27 04:16:44 +0000649
David Lawrence Ramsey1cb945f2017-02-14 21:35:01 -0600650 copy_from_buffer(u->cutbuffer);
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +0000651
Benno Schulenbergf0bb5032015-06-27 09:27:19 +0000652 if (u->xflags != WAS_MARKED_FORWARD && u->type != PASTE)
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +0000653 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
Chris Allegrettab549f372008-09-16 21:35:19 +0000654}
655
Benno Schulenberg189fff42014-04-04 20:45:28 +0000656/* Redo a cut, or undo an uncut. */
Benno Schulenbergd19be5a2014-04-08 18:38:45 +0000657void redo_cut(undo *u)
658{
Benno Schulenberg189fff42014-04-04 20:45:28 +0000659 /* If we cut the magicline, we may as well not crash. :/ */
Chris Allegretta42726f72009-07-27 04:16:44 +0000660 if (!u->cutbuffer)
661 return;
Chris Allegrettab549f372008-09-16 21:35:19 +0000662
Benno Schulenberg637b76b2014-07-02 20:52:27 +0000663 filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
Benno Schulenbergae22fe02015-12-01 11:51:10 +0000664 cutbuffer = cutbottom = NULL;
Benno Schulenberg637b76b2014-07-02 20:52:27 +0000665
Benno Schulenberg60815462014-05-15 20:00:46 +0000666 goto_line_posx(u->lineno, u->begin);
667
Benno Schulenberg92213f92014-07-02 20:29:57 +0000668 openfile->mark_set = TRUE;
Benno Schulenberg60815462014-05-15 20:00:46 +0000669 openfile->mark_begin = fsfromline(u->mark_begin_lineno);
Benno Schulenbergf0bb5032015-06-27 09:27:19 +0000670 openfile->mark_begin_x = (u->xflags == WAS_WHOLE_LINE) ? 0 : u->mark_begin_x;
Benno Schulenberg01666912014-06-22 11:03:49 +0000671
Benno Schulenberg452066b2015-11-02 13:46:40 +0000672 do_cut_text(FALSE, FALSE);
Benno Schulenberg01666912014-06-22 11:03:49 +0000673
Benno Schulenberg97039342016-02-18 19:58:18 +0000674 free_filestruct(cutbuffer);
Benno Schulenberg637b76b2014-07-02 20:52:27 +0000675 cutbuffer = oldcutbuffer;
676 cutbottom = oldcutbottom;
Chris Allegrettab549f372008-09-16 21:35:19 +0000677}
678
Benno Schulenberg189fff42014-04-04 20:45:28 +0000679/* Undo the last thing(s) we did. */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000680void do_undo(void)
681{
682 undo *u = openfile->current_undo;
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200683 filestruct *f, *t = NULL;
Benno Schulenberg5dde9182014-07-11 19:14:25 +0000684 char *data, *undidmsg = NULL;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000685
686 if (!u) {
687 statusbar(_("Nothing in undo buffer!"));
688 return;
689 }
690
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200691 f = fsfromline(u->mark_begin_lineno);
692 if (!f)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000693 return;
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200694
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000695#ifdef DEBUG
Benno Schulenberg3021a042015-06-17 15:17:09 +0000696 fprintf(stderr, " >> Undoing a type %d...\n", u->type);
697 fprintf(stderr, " >> Data we're about to undo = \"%s\"\n", f->data);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000698#endif
699
Chris Allegrettafa406942008-07-13 16:44:19 +0000700 openfile->current_x = u->begin;
Benno Schulenbergd19be5a2014-04-08 18:38:45 +0000701 switch (u->type) {
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000702 case ADD:
Benno Schulenbergcca22bb2016-02-05 12:27:54 +0000703 /* TRANSLATORS: Eight of the next nine strings describe actions
704 * that are undone or redone. It are all nouns, not verbs. */
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000705 undidmsg = _("text add");
Benno Schulenberg81f31772015-11-22 16:09:15 +0000706 data = charalloc(strlen(f->data) - strlen(u->strdata) + 1);
Benno Schulenberga9fdfd02014-07-16 08:53:16 +0000707 strncpy(data, f->data, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000708 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
709 free(f->data);
710 f->data = data;
Benno Schulenberg60815462014-05-15 20:00:46 +0000711 goto_line_posx(u->lineno, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000712 break;
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000713 case BACK:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000714 case DEL:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000715 undidmsg = _("text delete");
Benno Schulenberg81f31772015-11-22 16:09:15 +0000716 data = charalloc(strlen(f->data) + strlen(u->strdata) + 1);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000717 strncpy(data, f->data, u->begin);
718 strcpy(&data[u->begin], u->strdata);
719 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
720 free(f->data);
721 f->data = data;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +0000722 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000723 break;
Chris Allegrettac9f07992009-12-03 03:12:00 +0000724#ifndef DISABLE_WRAPPING
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +0000725 case SPLIT_END:
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +0000726 goto_line_posx(u->lineno, u->begin);
727 openfile->current_undo = openfile->current_undo->next;
728 openfile->last_action = OTHER;
729 while (openfile->current_undo->type != SPLIT_BEGIN)
730 do_undo();
731 u = openfile->current_undo;
732 f = openfile->current;
Benno Schulenberg5dde9182014-07-11 19:14:25 +0000733 case SPLIT_BEGIN:
734 undidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000735 break;
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000736#endif
Benno Schulenberg45fe2ad2014-06-18 20:11:52 +0000737 case JOIN:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000738 undidmsg = _("line join");
Benno Schulenberg82373d82015-06-17 10:41:57 +0000739 /* When the join was done by a Backspace at the tail of the file,
Benno Schulenberg61966642015-07-06 18:03:14 +0000740 * and the nonewlines flag isn't set, do not re-add a newline that
741 * wasn't actually deleted; just position the cursor. */
Benno Schulenbergf2da4662015-12-04 21:11:10 +0000742 if (u->xflags == WAS_FINAL_BACKSPACE && !ISSET(NO_NEWLINES)) {
Benno Schulenberg61966642015-07-06 18:03:14 +0000743 goto_line_posx(openfile->filebot->lineno, 0);
744 break;
745 }
Benno Schulenberg6095ff32015-07-06 19:17:27 +0000746 t = make_new_node(f);
747 t->data = mallocstrcpy(NULL, u->strdata);
748 data = mallocstrncpy(NULL, f->data, u->mark_begin_x + 1);
749 data[u->mark_begin_x] = '\0';
750 free(f->data);
751 f->data = data;
Benno Schulenbergfbe43762015-11-24 13:24:01 +0000752 splice_node(f, t);
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +0000753 goto_line_posx(u->lineno, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000754 break;
Benno Schulenberg60815462014-05-15 20:00:46 +0000755 case CUT_EOF:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000756 case CUT:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000757 undidmsg = _("text cut");
Benno Schulenberga9fdfd02014-07-16 08:53:16 +0000758 undo_cut(u);
Benno Schulenberg2394e522014-07-16 08:46:42 +0000759 f = fsfromline(u->lineno);
Chris Allegrettab549f372008-09-16 21:35:19 +0000760 break;
Benno Schulenberg60815462014-05-15 20:00:46 +0000761 case PASTE:
Chris Allegrettab549f372008-09-16 21:35:19 +0000762 undidmsg = _("text uncut");
Benno Schulenberg60815462014-05-15 20:00:46 +0000763 undo_paste(u);
Benno Schulenberg883373c2016-06-14 16:01:52 +0200764 f = fsfromline(u->mark_begin_lineno);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000765 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000766 case ENTER:
Benno Schulenbergb255b012015-11-25 09:49:27 +0000767 if (f->next == NULL) {
Benno Schulenberg2535f512016-04-30 17:31:43 +0200768 statusline(ALERT, _("Internal error: line is missing. "
769 "Please save your work."));
Benno Schulenbergb255b012015-11-25 09:49:27 +0000770 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000771 }
Benno Schulenbergb255b012015-11-25 09:49:27 +0000772 undidmsg = _("line break");
Benno Schulenberg1b69dd62015-11-25 09:27:25 +0000773 f->data = charealloc(f->data, strlen(f->data) +
774 strlen(&f->next->data[u->mark_begin_x]) + 1);
775 strcat(f->data, &f->next->data[u->mark_begin_x]);
Benno Schulenbergb255b012015-11-25 09:49:27 +0000776 unlink_node(f->next);
Benno Schulenberg60815462014-05-15 20:00:46 +0000777 goto_line_posx(u->lineno, u->begin);
Chris Allegrettab843a512009-04-21 05:34:08 +0000778 break;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200779#ifdef ENABLE_COMMENT
780 case COMMENT:
781 handle_comment_action(u, TRUE, TRUE);
782 undidmsg = _("comment");
783 break;
784 case UNCOMMENT:
785 handle_comment_action(u, TRUE, FALSE);
786 undidmsg = _("uncomment");
787 break;
788#endif
Chris Allegretta14c86202008-08-03 04:48:05 +0000789 case INSERT:
790 undidmsg = _("text insert");
Benno Schulenberg01666912014-06-22 11:03:49 +0000791 filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
Chris Allegretta14c86202008-08-03 04:48:05 +0000792 cutbuffer = NULL;
793 cutbottom = NULL;
Benno Schulenberg6007d622015-11-22 16:08:28 +0000794 /* Instead of a line number, u->mark_begin_lineno contains the number
795 * of lines of the inserted segment, because the file was partitioned
796 * when update_undo() was called; so, calculate the end-line number. */
Chris Allegretta14c86202008-08-03 04:48:05 +0000797 openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
Benno Schulenbergec26fd52015-11-12 19:01:57 +0000798 openfile->mark_begin_x = u->mark_begin_x;
Chris Allegretta14c86202008-08-03 04:48:05 +0000799 openfile->mark_set = TRUE;
Benno Schulenberg60815462014-05-15 20:00:46 +0000800 goto_line_posx(u->lineno, u->begin);
Benno Schulenbergd3429a72016-12-31 16:36:14 +0100801 cut_marked(NULL);
Benno Schulenberg97039342016-02-18 19:58:18 +0000802 free_filestruct(u->cutbuffer);
Chris Allegretta14c86202008-08-03 04:48:05 +0000803 u->cutbuffer = cutbuffer;
804 u->cutbottom = cutbottom;
805 cutbuffer = oldcutbuffer;
806 cutbottom = oldcutbottom;
807 openfile->mark_set = FALSE;
808 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000809 case REPLACE:
810 undidmsg = _("text replace");
Benno Schulenberg60815462014-05-15 20:00:46 +0000811 goto_line_posx(u->lineno, u->begin);
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000812 data = u->strdata;
813 u->strdata = f->data;
814 f->data = data;
815 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000816 default:
Benno Schulenberg2535f512016-04-30 17:31:43 +0200817 statusline(ALERT, _("Internal error: unknown type. "
818 "Please save your work."));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000819 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000820 }
Benno Schulenberg8f615112014-04-14 09:57:06 +0000821
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +0530822 if (undidmsg && !pletion_line)
Benno Schulenberg2535f512016-04-30 17:31:43 +0200823 statusline(HUSH, _("Undid action (%s)"), undidmsg);
Benno Schulenberg38cb8fc2014-06-17 15:37:34 +0000824
825 renumber(f);
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +0100826
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000827 openfile->current_undo = openfile->current_undo->next;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000828 openfile->last_action = OTHER;
Benno Schulenbergccffc542016-06-07 13:04:51 +0200829 openfile->mark_set = FALSE;
Benno Schulenberge96022b2014-06-17 15:50:34 +0000830 openfile->placewewant = xplustabs();
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +0100831
Benno Schulenberg66e21412015-11-30 16:21:51 +0000832 openfile->totsize = u->wassize;
Benno Schulenberg60815462014-05-15 20:00:46 +0000833 set_modified();
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000834}
835
Benno Schulenberg189fff42014-04-04 20:45:28 +0000836/* Redo the last thing(s) we undid. */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000837void do_redo(void)
838{
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200839 filestruct *f;
Benno Schulenberg5dde9182014-07-11 19:14:25 +0000840 char *data, *redidmsg = NULL;
Benno Schulenberg26eed9d2015-10-28 20:49:16 +0000841 undo *u = openfile->undotop;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000842
Benno Schulenbergbf645142015-10-29 17:02:13 +0000843 if (u == NULL || u == openfile->current_undo) {
844 statusbar(_("Nothing to re-do!"));
845 return;
846 }
847
Benno Schulenberg26eed9d2015-10-28 20:49:16 +0000848 /* Get the previous undo item. */
Benno Schulenbergd0b72552015-10-29 09:04:30 +0000849 while (u != NULL && u->next != openfile->current_undo)
Benno Schulenberg26eed9d2015-10-28 20:49:16 +0000850 u = u->next;
851
Benno Schulenbergbf645142015-10-29 17:02:13 +0000852 if (u->next != openfile->current_undo) {
Benno Schulenberg2535f512016-04-30 17:31:43 +0200853 statusline(ALERT, _("Internal error: cannot set up redo. "
854 "Please save your work."));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000855 return;
856 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000857
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200858 f = fsfromline(u->type == INSERT ? 1 : u->mark_begin_lineno);
859 if (!f)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000860 return;
Benno Schulenberg06b449b2016-05-08 10:51:40 +0200861
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000862#ifdef DEBUG
Benno Schulenbergf2da4662015-12-04 21:11:10 +0000863 fprintf(stderr, " >> Redo running for type %d\n", u->type);
864 fprintf(stderr, " >> Data we're about to redo = \"%s\"\n", f->data);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000865#endif
866
Benno Schulenbergd19be5a2014-04-08 18:38:45 +0000867 switch (u->type) {
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000868 case ADD:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000869 redidmsg = _("text add");
Benno Schulenberg81f31772015-11-22 16:09:15 +0000870 data = charalloc(strlen(f->data) + strlen(u->strdata) + 1);
Chris Allegretta1f37c452008-08-01 04:11:57 +0000871 strncpy(data, f->data, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000872 strcpy(&data[u->begin], u->strdata);
873 strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
874 free(f->data);
875 f->data = data;
Benno Schulenberg60815462014-05-15 20:00:46 +0000876 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000877 break;
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000878 case BACK:
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000879 case DEL:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000880 redidmsg = _("text delete");
Benno Schulenberg81f31772015-11-22 16:09:15 +0000881 data = charalloc(strlen(f->data) + strlen(u->strdata) + 1);
Benno Schulenberga9fdfd02014-07-16 08:53:16 +0000882 strncpy(data, f->data, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000883 strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
884 free(f->data);
885 f->data = data;
Benno Schulenberg60815462014-05-15 20:00:46 +0000886 goto_line_posx(u->lineno, u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000887 break;
Chris Allegrettab843a512009-04-21 05:34:08 +0000888 case ENTER:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000889 redidmsg = _("line break");
Benno Schulenbergf1d9fcc2015-11-11 18:51:39 +0000890 filestruct *shoveline = make_new_node(f);
891 shoveline->data = mallocstrcpy(NULL, u->strdata);
892 data = mallocstrncpy(NULL, f->data, u->begin + 1);
893 data[u->begin] = '\0';
894 free(f->data);
895 f->data = data;
Benno Schulenbergfbe43762015-11-24 13:24:01 +0000896 splice_node(f, shoveline);
Benno Schulenbergf1d9fcc2015-11-11 18:51:39 +0000897 renumber(shoveline);
898 goto_line_posx(u->lineno + 1, u->mark_begin_x);
Chris Allegrettab843a512009-04-21 05:34:08 +0000899 break;
Chris Allegrettac9f07992009-12-03 03:12:00 +0000900#ifndef DISABLE_WRAPPING
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +0000901 case SPLIT_BEGIN:
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +0000902 goto_line_posx(u->lineno, u->begin);
903 openfile->current_undo = u;
904 openfile->last_action = OTHER;
905 while (openfile->current_undo->type != SPLIT_END)
906 do_redo();
907 u = openfile->current_undo;
908 goto_line_posx(u->lineno, u->begin);
Benno Schulenberg5dde9182014-07-11 19:14:25 +0000909 case SPLIT_END:
910 redidmsg = _("text add");
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000911 break;
Benno Schulenberg953ccc92015-06-28 14:12:25 +0000912#endif
Benno Schulenberg45fe2ad2014-06-18 20:11:52 +0000913 case JOIN:
Benno Schulenberg4a59b122015-11-26 09:31:33 +0000914 if (f->next == NULL) {
Benno Schulenberg2535f512016-04-30 17:31:43 +0200915 statusline(ALERT, _("Internal error: line is missing. "
916 "Please save your work."));
Benno Schulenberg4a59b122015-11-26 09:31:33 +0000917 break;
918 }
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000919 redidmsg = _("line join");
Benno Schulenberg793d8492015-11-26 08:45:22 +0000920 /* When the join was done by a Backspace at the tail of the file,
921 * and the nonewlines flag isn't set, do not join anything, as
922 * nothing was actually deleted; just position the cursor. */
923 if (u->xflags == WAS_FINAL_BACKSPACE && !ISSET(NO_NEWLINES)) {
924 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
925 break;
926 }
Benno Schulenberg81f31772015-11-22 16:09:15 +0000927 f->data = charealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1);
Benno Schulenberg60815462014-05-15 20:00:46 +0000928 strcat(f->data, u->strdata);
Benno Schulenberg4a59b122015-11-26 09:31:33 +0000929 unlink_node(f->next);
Chris Allegretta0b499d42008-07-14 07:18:22 +0000930 renumber(f);
Benno Schulenberg64896ba2014-06-08 19:02:12 +0000931 goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000932 break;
Benno Schulenberg60815462014-05-15 20:00:46 +0000933 case CUT_EOF:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000934 case CUT:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000935 redidmsg = _("text cut");
Chris Allegrettab549f372008-09-16 21:35:19 +0000936 redo_cut(u);
937 break;
Benno Schulenberg60815462014-05-15 20:00:46 +0000938 case PASTE:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000939 redidmsg = _("text uncut");
Benno Schulenberg60815462014-05-15 20:00:46 +0000940 redo_paste(u);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +0000941 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000942 case REPLACE:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000943 redidmsg = _("text replace");
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000944 data = u->strdata;
945 u->strdata = f->data;
946 f->data = data;
Benno Schulenberg60815462014-05-15 20:00:46 +0000947 goto_line_posx(u->lineno, u->begin);
Chris Allegretta3c1131a2008-08-02 22:31:01 +0000948 break;
Chris Allegrettab549f372008-09-16 21:35:19 +0000949 case INSERT:
Benno Schulenberg4cf39e42014-06-22 21:26:56 +0000950 redidmsg = _("text insert");
Benno Schulenberg60815462014-05-15 20:00:46 +0000951 goto_line_posx(u->lineno, u->begin);
David Lawrence Ramsey1cb945f2017-02-14 21:35:01 -0600952 copy_from_buffer(u->cutbuffer);
Benno Schulenberg637b76b2014-07-02 20:52:27 +0000953 free_filestruct(u->cutbuffer);
954 u->cutbuffer = NULL;
Chris Allegrettaea577872008-08-03 20:19:42 +0000955 break;
Mike Scalora6a2032f2016-05-25 22:13:50 +0200956#ifdef ENABLE_COMMENT
957 case COMMENT:
958 handle_comment_action(u, FALSE, TRUE);
959 redidmsg = _("comment");
960 break;
961 case UNCOMMENT:
962 handle_comment_action(u, FALSE, FALSE);
963 redidmsg = _("uncomment");
964 break;
965#endif
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000966 default:
Benno Schulenberg2535f512016-04-30 17:31:43 +0200967 statusline(ALERT, _("Internal error: unknown type. "
968 "Please save your work."));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000969 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000970 }
Benno Schulenberg8f615112014-04-14 09:57:06 +0000971
Benno Schulenberg5dde9182014-07-11 19:14:25 +0000972 if (redidmsg)
Benno Schulenberg2535f512016-04-30 17:31:43 +0200973 statusline(HUSH, _("Redid action (%s)"), redidmsg);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000974
975 openfile->current_undo = u;
Chris Allegretta6f681c12008-08-08 03:02:03 +0000976 openfile->last_action = OTHER;
Benno Schulenbergccffc542016-06-07 13:04:51 +0200977 openfile->mark_set = FALSE;
Benno Schulenberge96022b2014-06-17 15:50:34 +0000978 openfile->placewewant = xplustabs();
Benno Schulenbergc0aa5ad2017-01-09 18:25:25 +0100979
Benno Schulenberg66e21412015-11-30 16:21:51 +0000980 openfile->totsize = u->newsize;
Benno Schulenberg60815462014-05-15 20:00:46 +0000981 set_modified();
Chris Allegretta07fcc4c2008-07-10 20:13:04 +0000982}
David Lawrence Ramseyf85001a2006-04-28 13:19:56 +0000983#endif /* !NANO_TINY */
984
Benno Schulenbergea9f62f2016-12-13 19:27:33 +0100985/* Break the current line at the cursor position. */
Benno Schulenberg9fa95a32016-12-15 13:04:52 +0100986void do_enter(void)
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000987{
988 filestruct *newnode = make_new_node(openfile->current);
989 size_t extra = 0;
990
Chris Allegrettadc7136a2008-08-21 04:24:25 +0000991 assert(openfile->current != NULL && openfile->current->data != NULL);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000992
David Lawrence Ramseyebe34252005-11-15 03:17:35 +0000993#ifndef NANO_TINY
Benno Schulenberg7be49302015-11-11 19:15:36 +0000994 add_undo(ENTER);
995
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000996 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +0000997 extra = indent_length(openfile->current->data);
Benno Schulenbergea9f62f2016-12-13 19:27:33 +0100998
999 /* If we are breaking the line in the indentation, limit the new
1000 * indentation to the current x position. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001001 if (extra > openfile->current_x)
1002 extra = openfile->current_x;
1003 }
1004#endif
1005 newnode->data = charalloc(strlen(openfile->current->data +
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001006 openfile->current_x) + extra + 1);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001007 strcpy(&newnode->data[extra], openfile->current->data +
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001008 openfile->current_x);
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001009#ifndef NANO_TINY
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001010 if (ISSET(AUTOINDENT)) {
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001011 /* Copy the whitespace from the current line to the new one. */
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001012 strncpy(newnode->data, openfile->current->data, extra);
Chris Allegrettadaeab052011-05-10 05:43:08 +00001013 openfile->totsize += extra;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001014 }
1015#endif
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001016
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001017 null_at(&openfile->current->data, openfile->current_x);
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001018
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001019#ifndef NANO_TINY
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001020 /* Adjust the mark if it was on the current line after the cursor. */
Benno Schulenberg953ccc92015-06-28 14:12:25 +00001021 if (openfile->mark_set && openfile->current == openfile->mark_begin &&
1022 openfile->current_x < openfile->mark_begin_x) {
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001023 openfile->mark_begin = newnode;
1024 openfile->mark_begin_x += extra - openfile->current_x;
1025 }
1026#endif
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001027
Benno Schulenbergfbe43762015-11-24 13:24:01 +00001028 splice_node(openfile->current, newnode);
Benno Schulenberg6007d622015-11-22 16:08:28 +00001029 renumber(newnode);
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001030
Benno Schulenbergea9f62f2016-12-13 19:27:33 +01001031 openfile->current = newnode;
1032 openfile->current_x = extra;
1033 openfile->placewewant = xplustabs();
1034
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001035 openfile->totsize++;
1036 set_modified();
David Lawrence Ramseyfeb89db2005-09-13 04:45:46 +00001037
Benno Schulenberg7be49302015-11-11 19:15:36 +00001038#ifndef NANO_TINY
1039 update_undo(ENTER);
1040#endif
1041
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02001042 refresh_needed = TRUE;
David Lawrence Ramsey7ea09e52005-07-25 02:41:59 +00001043}
1044
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001045#ifndef NANO_TINY
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001046/* Send a SIGKILL (unconditional kill) to the forked process in
1047 * execute_command(). */
David Lawrence Ramsey8befda62005-12-06 19:39:56 +00001048RETSIGTYPE cancel_command(int signal)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001049{
1050 if (kill(pid, SIGKILL) == -1)
1051 nperror("kill");
1052}
1053
David Lawrence Ramsey0ed71712005-11-08 23:09:47 +00001054/* Execute command in a shell. Return TRUE on success. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001055bool execute_command(const char *command)
1056{
1057 int fd[2];
1058 FILE *f;
David Lawrence Ramseyeae85712005-11-29 05:48:06 +00001059 char *shellenv;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001060 struct sigaction oldaction, newaction;
1061 /* Original and temporary handlers for SIGINT. */
1062 bool sig_failed = FALSE;
1063 /* Did sigaction() fail without changing the signal handlers? */
1064
1065 /* Make our pipes. */
1066 if (pipe(fd) == -1) {
Benno Schulenberg46fccb22014-02-28 11:49:12 +00001067 statusbar(_("Could not create pipe"));
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001068 return FALSE;
1069 }
1070
Benno Schulenberg189fff42014-04-04 20:45:28 +00001071 /* Check $SHELL for the shell to use. If it isn't set, use /bin/sh.
1072 * Note that $SHELL should contain only a path, with no arguments. */
David Lawrence Ramseyeae85712005-11-29 05:48:06 +00001073 shellenv = getenv("SHELL");
1074 if (shellenv == NULL)
Chris Allegretta5a018f02009-11-29 06:13:22 +00001075 shellenv = (char *) "/bin/sh";
David Lawrence Ramseyeae85712005-11-29 05:48:06 +00001076
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001077 /* Fork a child. */
1078 if ((pid = fork()) == 0) {
1079 close(fd[0]);
1080 dup2(fd[1], fileno(stdout));
1081 dup2(fd[1], fileno(stderr));
1082
1083 /* If execl() returns at all, there was an error. */
David Lawrence Ramsey5da68ee2005-11-29 05:21:06 +00001084 execl(shellenv, tail(shellenv), "-c", command, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001085 exit(0);
1086 }
1087
David Lawrence Ramseyc838a4c2006-04-26 18:33:50 +00001088 /* Continue as parent. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001089 close(fd[1]);
1090
1091 if (pid == -1) {
1092 close(fd[0]);
1093 statusbar(_("Could not fork"));
1094 return FALSE;
1095 }
1096
1097 /* Before we start reading the forked command's output, we set
1098 * things up so that Ctrl-C will cancel the new process. */
1099
1100 /* Enable interpretation of the special control keys so that we get
1101 * SIGINT when Ctrl-C is pressed. */
1102 enable_signals();
1103
1104 if (sigaction(SIGINT, NULL, &newaction) == -1) {
1105 sig_failed = TRUE;
1106 nperror("sigaction");
1107 } else {
1108 newaction.sa_handler = cancel_command;
1109 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
1110 sig_failed = TRUE;
1111 nperror("sigaction");
1112 }
1113 }
1114
1115 /* Note that now oldaction is the previous SIGINT signal handler,
1116 * to be restored later. */
1117
1118 f = fdopen(fd[0], "rb");
1119 if (f == NULL)
1120 nperror("fdopen");
1121
Chris Allegretta2c7b5062009-12-09 16:51:43 +00001122 read_file(f, 0, "stdin", TRUE, FALSE);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001123
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001124 if (wait(NULL) == -1)
1125 nperror("wait");
1126
1127 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
1128 nperror("sigaction");
1129
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +00001130 /* Restore the terminal to its previous state. In the process,
1131 * disable interpretation of the special control keys so that we can
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001132 * use Ctrl-C for other things. */
David Lawrence Ramsey8b9c91b2007-12-18 01:28:53 +00001133 terminal_init();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001134
1135 return TRUE;
1136}
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001137
Benno Schulenbergf8459382016-01-15 16:44:50 +00001138/* Discard undo items that are newer than the given one, or all if NULL. */
1139void discard_until(const undo *thisitem, openfilestruct *thefile)
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001140{
Benno Schulenbergf8459382016-01-15 16:44:50 +00001141 undo *dropit = thefile->undotop;
Mike Scalora6a2032f2016-05-25 22:13:50 +02001142 undo_group *group;
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001143
Benno Schulenbergf8459382016-01-15 16:44:50 +00001144 while (dropit != NULL && dropit != thisitem) {
1145 thefile->undotop = dropit->next;
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001146 free(dropit->strdata);
Benno Schulenberg97039342016-02-18 19:58:18 +00001147 free_filestruct(dropit->cutbuffer);
Mike Scalora6a2032f2016-05-25 22:13:50 +02001148#ifdef ENABLE_COMMENT
1149 group = dropit->grouping;
1150 while (group != NULL) {
1151 undo_group *next = group->next;
1152 free(group);
1153 group = next;
1154 }
1155#endif
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001156 free(dropit);
Benno Schulenbergf8459382016-01-15 16:44:50 +00001157 dropit = thefile->undotop;
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001158 }
Benno Schulenbergef2cfa32016-02-10 08:49:23 +00001159
Benno Schulenbergd21a9c82016-12-23 22:12:48 +01001160 /* Adjust the pointer to the top of the undo stack. */
1161 thefile->current_undo = (undo *)thisitem;
1162
Benno Schulenbergef2cfa32016-02-10 08:49:23 +00001163 /* Prevent a chain of editing actions from continuing. */
1164 thefile->last_action = OTHER;
Benno Schulenbergee5cdcb2015-12-03 08:50:34 +00001165}
1166
Benno Schulenberg189fff42014-04-04 20:45:28 +00001167/* Add a new undo struct to the top of the current pile. */
Benno Schulenberg86cbd952015-06-17 11:18:20 +00001168void add_undo(undo_type action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001169{
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001170 undo *u = openfile->current_undo;
Benno Schulenberg64041012015-06-17 10:59:16 +00001171 /* The thing we did previously. */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001172
Benno Schulenberg64041012015-06-17 10:59:16 +00001173 /* When doing contiguous adds or contiguous cuts -- which means: with
1174 * no cursor movement in between -- don't add a new undo item. */
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001175 if (u && u->mark_begin_lineno == openfile->current->lineno && action == openfile->last_action &&
1176 ((action == ADD && u->type == ADD && u->mark_begin_x == openfile->current_x) ||
Benno Schulenberg83b89a42016-06-07 11:52:57 +02001177 (action == CUT && u->type == CUT && u->xflags < MARK_WAS_SET && keeping_cutbuffer())))
Chris Allegretta8f761122008-08-01 06:52:15 +00001178 return;
1179
Benno Schulenberg6007d622015-11-22 16:08:28 +00001180 /* Blow away newer undo items if we add somewhere in the middle. */
Benno Schulenbergf8459382016-01-15 16:44:50 +00001181 discard_until(u, openfile);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001182
Benno Schulenberg3021a042015-06-17 15:17:09 +00001183#ifdef DEBUG
1184 fprintf(stderr, " >> Adding an undo...\n");
1185#endif
1186
Benno Schulenberg189fff42014-04-04 20:45:28 +00001187 /* Allocate and initialize a new undo type. */
Chris Allegretta5a018f02009-11-29 06:13:22 +00001188 u = (undo *) nmalloc(sizeof(undo));
Benno Schulenberg86cbd952015-06-17 11:18:20 +00001189 u->type = action;
Benno Schulenbergc35eb5a2014-06-09 10:35:44 +00001190#ifndef DISABLE_WRAPPING
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001191 if (u->type == SPLIT_BEGIN) {
1192 /* Some action, most likely an ADD, was performed that invoked
1193 * do_wrap(). Rearrange the undo order so that this previous
1194 * action is after the SPLIT_BEGIN undo. */
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001195 u->next = openfile->undotop->next;
1196 openfile->undotop->next = u;
Benno Schulenbergc35eb5a2014-06-09 10:35:44 +00001197 } else
1198#endif
1199 {
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001200 u->next = openfile->undotop;
1201 openfile->undotop = u;
1202 openfile->current_undo = u;
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001203 }
Chris Allegretta91a18622008-08-01 03:50:20 +00001204 u->strdata = NULL;
1205 u->cutbuffer = NULL;
Benno Schulenberg52e35332014-05-16 11:03:04 +00001206 u->cutbottom = NULL;
Benno Schulenberg6007d622015-11-22 16:08:28 +00001207 u->lineno = openfile->current->lineno;
1208 u->begin = openfile->current_x;
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001209 u->mark_begin_lineno = openfile->current->lineno;
1210 u->mark_begin_x = openfile->current_x;
Benno Schulenberg66e21412015-11-30 16:21:51 +00001211 u->wassize = openfile->totsize;
Chris Allegretta91a18622008-08-01 03:50:20 +00001212 u->xflags = 0;
Mike Scalora6a2032f2016-05-25 22:13:50 +02001213 u->grouping = NULL;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001214
1215 switch (u->type) {
Benno Schulenberg189fff42014-04-04 20:45:28 +00001216 /* We need to start copying data into the undo buffer
1217 * or we won't be able to restore it later. */
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001218 case ADD:
Benno Schulenberg66e21412015-11-30 16:21:51 +00001219 u->wassize--;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001220 break;
Benno Schulenberg64896ba2014-06-08 19:02:12 +00001221 case BACK:
Benno Schulenberg412b9fc2015-06-27 09:17:36 +00001222 /* If the next line is the magic line, don't ever undo this
1223 * backspace, as it won't actually have deleted anything. */
Benno Schulenberg964c10d2016-12-07 19:56:27 +01001224 if (openfile->current->next == openfile->filebot &&
1225 openfile->current->data[0] != '\0')
Benno Schulenbergf0bb5032015-06-27 09:27:19 +00001226 u->xflags = WAS_FINAL_BACKSPACE;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001227 case DEL:
Benno Schulenberg6620acb2016-12-20 10:03:53 +01001228 if (openfile->current->data[openfile->current_x] != '\0') {
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001229 char *char_buf = charalloc(mb_cur_max() + 1);
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001230 int char_len = parse_mbchar(&openfile->current->data[u->begin],
Benno Schulenberg964c10d2016-12-07 19:56:27 +01001231 char_buf, NULL);
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001232 null_at(&char_buf, char_len);
Benno Schulenberg1eb23d42014-06-04 16:30:11 +00001233 u->strdata = char_buf;
Benno Schulenberg64896ba2014-06-08 19:02:12 +00001234 if (u->type == BACK)
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001235 u->mark_begin_x += char_len;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001236 break;
1237 }
Benno Schulenberg45fe2ad2014-06-18 20:11:52 +00001238 /* Else purposely fall into the line-joining code. */
1239 case JOIN:
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001240 if (openfile->current->next) {
Benno Schulenberg64896ba2014-06-08 19:02:12 +00001241 if (u->type == BACK) {
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001242 u->lineno = openfile->current->next->lineno;
Benno Schulenberg64896ba2014-06-08 19:02:12 +00001243 u->begin = 0;
1244 }
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001245 u->strdata = mallocstrcpy(NULL, openfile->current->next->data);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001246 }
Benno Schulenberg86cbd952015-06-17 11:18:20 +00001247 action = u->type = JOIN;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001248 break;
Chris Allegrettac9f07992009-12-03 03:12:00 +00001249#ifndef DISABLE_WRAPPING
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001250 case SPLIT_BEGIN:
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001251 action = openfile->undotop->type;
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001252 break;
1253 case SPLIT_END:
Chris Allegretta12ba5572009-03-26 01:01:48 +00001254 break;
Benno Schulenberg953ccc92015-06-28 14:12:25 +00001255#endif
Chris Allegretta12ba5572009-03-26 01:01:48 +00001256 case INSERT:
Benno Schulenberg637b76b2014-07-02 20:52:27 +00001257 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001258 case REPLACE:
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001259 u->strdata = mallocstrcpy(NULL, openfile->current->data);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001260 break;
Benno Schulenberg60815462014-05-15 20:00:46 +00001261 case CUT_EOF:
Benno Schulenberg76e150b2014-06-21 19:32:17 +00001262 cutbuffer_reset();
1263 break;
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001264 case CUT:
Benno Schulenberga8727092014-06-18 19:04:35 +00001265 cutbuffer_reset();
Benno Schulenberg83b89a42016-06-07 11:52:57 +02001266 if (openfile->mark_set) {
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001267 u->mark_begin_lineno = openfile->mark_begin->lineno;
1268 u->mark_begin_x = openfile->mark_begin_x;
Benno Schulenberg83b89a42016-06-07 11:52:57 +02001269 u->xflags = MARK_WAS_SET;
Benno Schulenberg6007d622015-11-22 16:08:28 +00001270 } else if (!ISSET(CUT_TO_END)) {
Benno Schulenberg60815462014-05-15 20:00:46 +00001271 /* The entire line is being cut regardless of the cursor position. */
1272 u->begin = 0;
Benno Schulenbergf0bb5032015-06-27 09:27:19 +00001273 u->xflags = WAS_WHOLE_LINE;
Benno Schulenberg60815462014-05-15 20:00:46 +00001274 }
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001275 break;
Benno Schulenberg60815462014-05-15 20:00:46 +00001276 case PASTE:
Benno Schulenbergd6bd2762015-11-22 16:07:23 +00001277 u->cutbuffer = copy_filestruct(cutbuffer);
1278 u->lineno += cutbottom->lineno - cutbuffer->lineno;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001279 break;
Chris Allegrettab843a512009-04-21 05:34:08 +00001280 case ENTER:
1281 break;
Mike Scalora6a2032f2016-05-25 22:13:50 +02001282#ifdef ENABLE_COMMENT
1283 case COMMENT:
1284 case UNCOMMENT:
1285 break;
1286#endif
Benno Schulenberg530c7862015-11-25 10:11:54 +00001287 default:
Benno Schulenberg2535f512016-04-30 17:31:43 +02001288 statusline(ALERT, _("Internal error: unknown type. "
1289 "Please save your work."));
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001290 break;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001291 }
1292
1293#ifdef DEBUG
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001294 fprintf(stderr, " >> openfile->current->data = \"%s\", current_x = %lu, u->begin = %lu, type = %d\n",
1295 openfile->current->data, (unsigned long)openfile->current_x, (unsigned long)u->begin, action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001296#endif
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001297 openfile->last_action = action;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001298}
1299
Mike Scalora6a2032f2016-05-25 22:13:50 +02001300#ifdef ENABLE_COMMENT
Mike Scalora6a2032f2016-05-25 22:13:50 +02001301/* Update a comment undo item. This should be called once for each line
1302 * affected by the comment/uncomment feature. */
1303void update_comment_undo(ssize_t lineno)
1304{
1305 undo *u = openfile->current_undo;
1306
1307 /* If there already is a group and the current line is contiguous with it,
1308 * extend the group; otherwise, create a new group. */
1309 if (u->grouping && u->grouping->bottom_line + 1 == lineno)
1310 u->grouping->bottom_line++;
1311 else {
1312 undo_group *born = (undo_group *)nmalloc(sizeof(undo_group));
1313
1314 born->next = u->grouping;
1315 u->grouping = born;
1316 born->top_line = lineno;
1317 born->bottom_line = lineno;
1318 }
Mike Scalora115aeda2016-05-31 21:19:50 +02001319
1320 /* Store the file size after the change, to be used when redoing. */
1321 u->newsize = openfile->totsize;
Mike Scalora6a2032f2016-05-25 22:13:50 +02001322}
1323#endif /* ENABLE_COMMENT */
1324
Benno Schulenberg189fff42014-04-04 20:45:28 +00001325/* Update an undo item, or determine whether a new one is really needed
1326 * and bounce the data to add_undo instead. The latter functionality
1327 * just feels gimmicky and may just be more hassle than it's worth,
1328 * so it should be axed if needed. */
Chris Allegretta14c86202008-08-03 04:48:05 +00001329void update_undo(undo_type action)
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001330{
1331 undo *u;
Chris Allegretta91a18622008-08-01 03:50:20 +00001332
1333#ifdef DEBUG
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001334fprintf(stderr, " >> Updating... action = %d, openfile->last_action = %d, openfile->current->lineno = %ld",
1335 action, openfile->last_action, (long)openfile->current->lineno);
1336 if (openfile->current_undo)
1337 fprintf(stderr, ", openfile->current_undo->lineno = %ld\n", (long)openfile->current_undo->lineno);
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001338 else
1339 fprintf(stderr, "\n");
Chris Allegretta91a18622008-08-01 03:50:20 +00001340#endif
1341
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001342 /* Change to an add if we're not using the same undo struct
Benno Schulenberg189fff42014-04-04 20:45:28 +00001343 * that we should be using. */
Benno Schulenberg6007d622015-11-22 16:08:28 +00001344 if (action != openfile->last_action ||
1345 (action != ENTER && action != CUT && action != INSERT &&
1346 openfile->current->lineno != openfile->current_undo->lineno)) {
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00001347 add_undo(action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001348 return;
1349 }
1350
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001351 assert(openfile->undotop != NULL);
1352 u = openfile->undotop;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001353
Benno Schulenberg66e21412015-11-30 16:21:51 +00001354 u->newsize = openfile->totsize;
1355
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001356 switch (u->type) {
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001357 case ADD: {
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001358#ifdef DEBUG
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001359 fprintf(stderr, " >> openfile->current->data = \"%s\", current_x = %lu, u->begin = %lu\n",
1360 openfile->current->data, (unsigned long)openfile->current_x, (unsigned long)u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001361#endif
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001362 char *char_buf = charalloc(mb_cur_max());
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001363 int char_len = parse_mbchar(&openfile->current->data[u->mark_begin_x], char_buf, NULL);
1364 u->strdata = addstrings(u->strdata, u->strdata ? strlen(u->strdata) : 0, char_buf, char_len);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001365#ifdef DEBUG
Benno Schulenberg08d9f572015-07-10 17:25:51 +00001366 fprintf(stderr, " >> current undo data is \"%s\"\n", u->strdata);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001367#endif
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001368 u->mark_begin_lineno = openfile->current->lineno;
1369 u->mark_begin_x = openfile->current_x;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001370 break;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001371 }
Benno Schulenberg64896ba2014-06-08 19:02:12 +00001372 case BACK:
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001373 case DEL: {
1374 char *char_buf = charalloc(mb_cur_max());
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001375 int char_len = parse_mbchar(&openfile->current->data[openfile->current_x], char_buf, NULL);
Benno Schulenberg322120c2017-01-08 11:05:52 +01001376 if (openfile->current_x == u->begin) {
1377 /* They deleted more: add removed character after earlier stuff. */
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001378 u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, char_len);
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001379 u->mark_begin_x = openfile->current_x;
Benno Schulenberg322120c2017-01-08 11:05:52 +01001380 } else if (openfile->current_x == u->begin - char_len) {
1381 /* They backspaced further: add removed character before earlier. */
Benno Schulenberg79a4bf82016-12-19 19:58:15 +01001382 u->strdata = addstrings(char_buf, char_len, u->strdata, strlen(u->strdata));
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001383 u->begin = openfile->current_x;
Benno Schulenberg322120c2017-01-08 11:05:52 +01001384 } else {
1385 /* They deleted *elsewhere* on the line: start a new undo item. */
1386 free(char_buf);
1387 add_undo(u->type);
1388 return;
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001389 }
1390#ifdef DEBUG
Benno Schulenberg3021a042015-06-17 15:17:09 +00001391 fprintf(stderr, " >> current undo data is \"%s\"\nu->begin = %lu\n", u->strdata, (unsigned long)u->begin);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001392#endif
1393 break;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001394 }
Benno Schulenberg60815462014-05-15 20:00:46 +00001395 case CUT_EOF:
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001396 case CUT:
Chris Allegrettac84e7652008-10-14 01:14:12 +00001397 if (!cutbuffer)
1398 break;
Benno Schulenberg97039342016-02-18 19:58:18 +00001399 free_filestruct(u->cutbuffer);
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001400 u->cutbuffer = copy_filestruct(cutbuffer);
Benno Schulenberg83b89a42016-06-07 11:52:57 +02001401 if (u->xflags == MARK_WAS_SET) {
Benno Schulenberg60815462014-05-15 20:00:46 +00001402 /* If the "marking" operation was from right-->left or
1403 * bottom-->top, then swap the mark points. */
1404 if ((u->lineno == u->mark_begin_lineno && u->begin < u->mark_begin_x)
1405 || u->lineno < u->mark_begin_lineno) {
1406 size_t x_loc = u->begin;
1407 u->begin = u->mark_begin_x;
1408 u->mark_begin_x = x_loc;
1409
1410 ssize_t line = u->lineno;
1411 u->lineno = u->mark_begin_lineno;
1412 u->mark_begin_lineno = line;
Benno Schulenberg92213f92014-07-02 20:29:57 +00001413 } else
Benno Schulenbergf0bb5032015-06-27 09:27:19 +00001414 u->xflags = WAS_MARKED_FORWARD;
Benno Schulenberg92213f92014-07-02 20:29:57 +00001415 } else {
Benno Schulenbergf2da4662015-12-04 21:11:10 +00001416 /* Compute the end of the cut for the undo, using our copy. */
Benno Schulenberg60815462014-05-15 20:00:46 +00001417 u->cutbottom = u->cutbuffer;
1418 while (u->cutbottom->next != NULL)
1419 u->cutbottom = u->cutbottom->next;
Benno Schulenbergf2da4662015-12-04 21:11:10 +00001420 u->lineno = u->mark_begin_lineno + u->cutbottom->lineno -
1421 u->cutbuffer->lineno;
Benno Schulenberg92213f92014-07-02 20:29:57 +00001422 if (ISSET(CUT_TO_END) || u->type == CUT_EOF) {
1423 u->begin = strlen(u->cutbottom->data);
Benno Schulenberg953ccc92015-06-28 14:12:25 +00001424 if (u->lineno == u->mark_begin_lineno)
1425 u->begin += u->mark_begin_x;
Benno Schulenberg6b156602015-11-30 15:49:37 +00001426 } else if (openfile->current == openfile->filebot &&
1427 ISSET(NO_NEWLINES))
1428 u->begin = strlen(u->cutbottom->data);
Benno Schulenberg60815462014-05-15 20:00:46 +00001429 }
Chris Allegretta12dc8ca2008-07-31 04:24:04 +00001430 break;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001431 case REPLACE:
Benno Schulenberg60815462014-05-15 20:00:46 +00001432 case PASTE:
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001433 u->begin = openfile->current_x;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001434 u->lineno = openfile->current->lineno;
Chris Allegretta3c1131a2008-08-02 22:31:01 +00001435 break;
Chris Allegretta14c86202008-08-03 04:48:05 +00001436 case INSERT:
Benno Schulenberg6007d622015-11-22 16:08:28 +00001437 /* Store the number of lines (plus one) of the insertion. */
Chris Allegretta14c86202008-08-03 04:48:05 +00001438 u->mark_begin_lineno = openfile->current->lineno;
Benno Schulenbergec26fd52015-11-12 19:01:57 +00001439 /* When the insertion contains no newline, store the adjusted
1440 * x position; otherwise, store the length of the last line. */
1441 if (openfile->fileage == openfile->filebot)
1442 u->mark_begin_x = openfile->current_x;
1443 else
1444 u->mark_begin_x = strlen(openfile->filebot->data);
Chris Allegretta12ba5572009-03-26 01:01:48 +00001445 break;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001446 case ENTER:
Benno Schulenbergf9274a52015-11-12 19:50:33 +00001447 u->strdata = mallocstrcpy(NULL, openfile->current->data);
1448 u->mark_begin_x = openfile->current_x;
Benno Schulenbergf5ac8c12014-05-25 19:41:49 +00001449 break;
Chris Allegrettac9f07992009-12-03 03:12:00 +00001450#ifndef DISABLE_WRAPPING
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001451 case SPLIT_BEGIN:
1452 case SPLIT_END:
Benno Schulenberg953ccc92015-06-28 14:12:25 +00001453#endif
Benno Schulenberg45fe2ad2014-06-18 20:11:52 +00001454 case JOIN:
Benno Schulenberg189fff42014-04-04 20:45:28 +00001455 /* These cases are handled by the earlier check for a new line and action. */
Benno Schulenberg530c7862015-11-25 10:11:54 +00001456 break;
1457 default:
Benno Schulenberg2535f512016-04-30 17:31:43 +02001458 statusline(ALERT, _("Internal error: unknown type. "
1459 "Please save your work."));
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001460 break;
1461 }
1462
1463#ifdef DEBUG
Benno Schulenberg3021a042015-06-17 15:17:09 +00001464 fprintf(stderr, " >> Done in update_undo (type was %d)\n", action);
Chris Allegretta07fcc4c2008-07-10 20:13:04 +00001465#endif
Benno Schulenberga81e1412014-06-18 21:23:50 +00001466}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001467#endif /* !NANO_TINY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001468
1469#ifndef DISABLE_WRAPPING
David Lawrence Ramseyef0d5a72006-05-22 02:08:49 +00001470/* Unset the prepend_wrap flag. We need to do this as soon as we do
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00001471 * something other than type text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001472void wrap_reset(void)
1473{
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001474 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001475}
1476
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001477/* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */
1478bool do_wrap(filestruct *line)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001479{
1480 size_t line_len;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001481 /* The length of the line we wrap. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001482 ssize_t wrap_loc;
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001483 /* The index of line->data where we wrap. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001484 const char *after_break;
1485 /* The text after the wrap point. */
1486 size_t after_break_len;
1487 /* The length of after_break. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001488 const char *next_line = NULL;
1489 /* The next line, minus indentation. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00001490 size_t next_line_len = 0;
1491 /* The length of next_line. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001492
1493 /* There are three steps. First, we decide where to wrap. Then, we
1494 * create the new wrap line. Finally, we clean up. */
1495
1496 /* Step 1, finding where to wrap. We are going to add a new line
1497 * after a blank character. In this step, we call break_line() to
1498 * get the location of the last blank we can break the line at, and
David Lawrence Ramseyd4686b82006-06-11 19:14:14 +00001499 * set wrap_loc to the location of the character after it, so that
1500 * the blank is preserved at the end of the line.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001501 *
1502 * If there is no legal wrap point, or we reach the last character
1503 * of the line while trying to find one, we should return without
1504 * wrapping. Note that if autoindent is turned on, we don't break
1505 * at the end of it! */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001506 assert(line != NULL && line->data != NULL);
1507
1508 /* Save the length of the line. */
1509 line_len = strlen(line->data);
1510
1511 /* Find the last blank where we can break the line. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001512 wrap_loc = break_line(line->data, fill
1513#ifndef DISABLE_HELP
1514 , FALSE
1515#endif
1516 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001517
1518 /* If we couldn't break the line, or we've reached the end of it, we
1519 * don't wrap. */
1520 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
1521 return FALSE;
1522
1523 /* Otherwise, move forward to the character just after the blank. */
1524 wrap_loc += move_mbright(line->data + wrap_loc, 0);
1525
1526 /* If we've reached the end of the line, we don't wrap. */
1527 if (line->data[wrap_loc] == '\0')
1528 return FALSE;
1529
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001530#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001531 /* If autoindent is turned on, and we're on the character just after
1532 * the indentation, we don't wrap. */
Benno Schulenbergd0e88872015-11-02 11:24:22 +00001533 if (ISSET(AUTOINDENT) && wrap_loc == indent_length(line->data))
1534 return FALSE;
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001535
1536 add_undo(SPLIT_BEGIN);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001537#endif
1538
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001539 size_t old_x = openfile->current_x;
1540 filestruct * oldLine = openfile->current;
1541 openfile->current = line;
1542
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001543 /* Step 2, making the new wrap line. It will consist of indentation
1544 * followed by the text after the wrap point, optionally followed by
1545 * a space (if the text after the wrap point doesn't end in a blank)
David Lawrence Ramsey03979d72006-06-11 19:15:59 +00001546 * and the text of the next line, if they can fit without wrapping,
1547 * the next line exists, and the prepend_wrap flag is set. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001548
1549 /* after_break is the text that will be wrapped to the next line. */
1550 after_break = line->data + wrap_loc;
1551 after_break_len = line_len - wrap_loc;
1552
1553 assert(strlen(after_break) == after_break_len);
1554
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001555 /* We prepend the wrapped text to the next line, if the prepend_wrap
1556 * flag is set, there is a next line, and prepending would not make
1557 * the line too long. */
1558 if (prepend_wrap && line != openfile->filebot) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001559 const char *end = after_break + move_mbleft(after_break,
1560 after_break_len);
1561
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001562 /* Go to the end of the line. */
1563 openfile->current_x = line_len;
1564
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001565 /* If after_break doesn't end in a blank, make sure it ends in a
1566 * space. */
Chris Allegretta9f983332016-02-25 21:04:45 +00001567 if (!is_blank_mbchar(end) && !ISSET(JUSTIFY_TRIM)) {
Benno Schulenberg3b47ff72014-06-20 16:13:54 +00001568#ifndef NANO_TINY
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001569 add_undo(ADD);
Benno Schulenberg3b47ff72014-06-20 16:13:54 +00001570#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001571 line_len++;
1572 line->data = charealloc(line->data, line_len + 1);
1573 line->data[line_len - 1] = ' ';
1574 line->data[line_len] = '\0';
1575 after_break = line->data + wrap_loc;
1576 after_break_len++;
1577 openfile->totsize++;
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001578 openfile->current_x++;
Benno Schulenberg3b47ff72014-06-20 16:13:54 +00001579#ifndef NANO_TINY
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001580 update_undo(ADD);
Benno Schulenberg3b47ff72014-06-20 16:13:54 +00001581#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001582 }
1583
1584 next_line = line->next->data;
1585 next_line_len = strlen(next_line);
1586
1587 if (after_break_len + next_line_len <= fill) {
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001588 /* Delete the LF to join the two lines. */
1589 do_delete();
1590 /* Delete any leading blanks from the joined-on line. */
1591 while (is_blank_mbchar(&line->data[openfile->current_x]))
1592 do_delete();
1593 renumber(line);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001594 }
1595 }
1596
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001597 /* Go to the wrap location and split the line there. */
1598 openfile->current_x = wrap_loc;
Benno Schulenberg54c2f6b2015-11-11 19:04:31 +00001599 do_enter();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001600
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001601 if (old_x < wrap_loc) {
1602 openfile->current_x = old_x;
1603 openfile->current = oldLine;
1604 prepend_wrap = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001605 } else {
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001606 openfile->current_x += (old_x - wrap_loc);
David Lawrence Ramseyb4e5c022005-11-25 13:48:09 +00001607 prepend_wrap = FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001608 }
1609
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001610 openfile->placewewant = xplustabs();
1611
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001612#ifndef NANO_TINY
Benno Schulenbergbe10c2a2014-06-09 10:01:54 +00001613 add_undo(SPLIT_END);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001614#endif
1615
1616 return TRUE;
1617}
1618#endif /* !DISABLE_WRAPPING */
1619
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001620#if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001621/* We are trying to break a chunk off line. We find the last blank such
David Lawrence Ramseycd9a5f02005-09-20 06:12:54 +00001622 * that the display length to there is at most (goal + 1). If there is
1623 * no such blank, then we find the first blank. We then take the last
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001624 * blank in that group of blanks. The terminating '\0' counts as a
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001625 * blank, as does a '\n' if newln is TRUE. */
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001626ssize_t break_line(const char *line, ssize_t goal
1627#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001628 , bool newln
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001629#endif
1630 )
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001631{
1632 ssize_t blank_loc = -1;
1633 /* Current tentative return value. Index of the last blank we
Benno Schulenberg8f615112014-04-14 09:57:06 +00001634 * found with short enough display width. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001635 ssize_t cur_loc = 0;
1636 /* Current index in line. */
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001637 size_t cur_pos = 0;
1638 /* Current column position in line. */
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001639 int char_len = 0;
1640 /* Length of current character, in bytes. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001641
1642 assert(line != NULL);
1643
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001644 while (*line != '\0' && goal >= cur_pos) {
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001645 char_len = parse_mbchar(line, NULL, &cur_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001646
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001647 if (is_blank_mbchar(line)
1648#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001649 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001650#endif
1651 ) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001652 blank_loc = cur_loc;
1653
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001654#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001655 if (newln && *line == '\n')
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001656 break;
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001657#endif
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001658 }
1659
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001660 line += char_len;
1661 cur_loc += char_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001662 }
1663
David Lawrence Ramsey2d3d1e92006-05-18 17:28:16 +00001664 if (goal >= cur_pos)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001665 /* In fact, the whole line displays shorter than goal. */
1666 return cur_loc;
1667
Chris Allegretta09b81242008-07-12 01:54:49 +00001668#ifndef DISABLE_HELP
1669 if (newln && blank_loc <= 0) {
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00001670 /* If no blank was found, or was found only as the first
1671 * character, force a line break. */
1672 cur_loc -= char_len;
1673 return cur_loc;
Chris Allegretta09b81242008-07-12 01:54:49 +00001674 }
1675#endif
1676
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001677 if (blank_loc == -1) {
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001678 /* No blank was found within the goal width,
1679 * so now try and find a blank beyond it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001680 bool found_blank = FALSE;
David Lawrence Ramsey5ab12ca2005-09-20 17:52:52 +00001681 ssize_t found_blank_loc = 0;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001682
1683 while (*line != '\0') {
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001684 char_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001685
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001686 if (is_blank_mbchar(line)
1687#ifndef DISABLE_HELP
Chris Allegretta8b6461f2008-05-31 23:09:40 +00001688 || (newln && *line == '\n')
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00001689#endif
1690 ) {
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001691 found_blank = TRUE;
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001692 found_blank_loc = cur_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001693 } else if (found_blank)
David Lawrence Ramseybdc1b9b2005-09-20 16:36:08 +00001694 return found_blank_loc;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001695
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001696 line += char_len;
1697 cur_loc += char_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001698 }
1699
1700 return -1;
1701 }
1702
1703 /* Move to the last blank after blank_loc, if there is one. */
1704 line -= cur_loc;
1705 line += blank_loc;
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001706 char_len = parse_mbchar(line, NULL, NULL);
1707 line += char_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001708
Benno Schulenberga81e1412014-06-18 21:23:50 +00001709 while (*line != '\0' && is_blank_mbchar(line)) {
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001710 char_len = parse_mbchar(line, NULL, NULL);
David Lawrence Ramsey39bd1b32006-05-20 13:11:56 +00001711
Benno Schulenbergcd634e02014-04-14 13:02:43 +00001712 line += char_len;
1713 blank_loc += char_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001714 }
1715
1716 return blank_loc;
1717}
David Lawrence Ramseyc7c04bb2005-11-29 21:30:00 +00001718#endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001719
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001720#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001721/* The "indentation" of a line is the whitespace between the quote part
1722 * and the non-whitespace of the line. */
1723size_t indent_length(const char *line)
1724{
1725 size_t len = 0;
1726 char *blank_mb;
1727 int blank_mb_len;
1728
1729 assert(line != NULL);
1730
1731 blank_mb = charalloc(mb_cur_max());
1732
1733 while (*line != '\0') {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001734 blank_mb_len = parse_mbchar(line, blank_mb, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001735
1736 if (!is_blank_mbchar(blank_mb))
1737 break;
1738
1739 line += blank_mb_len;
1740 len += blank_mb_len;
1741 }
1742
1743 free(blank_mb);
1744
1745 return len;
1746}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001747#endif /* !NANO_TINY || !DISABLE_JUSTIFY */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001748
1749#ifndef DISABLE_JUSTIFY
1750/* justify_format() replaces blanks with spaces and multiple spaces by 1
1751 * (except it maintains up to 2 after a character in punct optionally
1752 * followed by a character in brackets, and removes all from the end).
1753 *
1754 * justify_format() might make paragraph->data shorter, and change the
1755 * actual pointer with null_at().
1756 *
1757 * justify_format() will not look at the first skip characters of
1758 * paragraph. skip should be at most strlen(paragraph->data). The
1759 * character at paragraph[skip + 1] must not be blank. */
1760void justify_format(filestruct *paragraph, size_t skip)
1761{
1762 char *end, *new_end, *new_paragraph_data;
1763 size_t shift = 0;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001764#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001765 size_t mark_shift = 0;
1766#endif
1767
1768 /* These four asserts are assumptions about the input data. */
1769 assert(paragraph != NULL);
1770 assert(paragraph->data != NULL);
1771 assert(skip < strlen(paragraph->data));
1772 assert(!is_blank_mbchar(paragraph->data + skip));
1773
1774 end = paragraph->data + skip;
1775 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
1776 strncpy(new_paragraph_data, paragraph->data, skip);
1777 new_end = new_paragraph_data + skip;
1778
1779 while (*end != '\0') {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001780 int end_len;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001781
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001782 /* If this character is blank, change it to a space if
1783 * necessary, and skip over all blanks after it. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001784 if (is_blank_mbchar(end)) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001785 end_len = parse_mbchar(end, NULL, NULL);
1786
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001787 *new_end = ' ';
1788 new_end++;
1789 end += end_len;
1790
1791 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001792 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001793
1794 end += end_len;
1795 shift += end_len;
1796
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001797#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001798 /* Keep track of the change in the current line. */
1799 if (openfile->mark_set && openfile->mark_begin ==
1800 paragraph && openfile->mark_begin_x >= end -
1801 paragraph->data)
1802 mark_shift += end_len;
1803#endif
1804 }
1805 /* If this character is punctuation optionally followed by a
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001806 * bracket and then followed by blanks, change no more than two
1807 * of the blanks to spaces if necessary, and skip over all
1808 * blanks after them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001809 } else if (mbstrchr(punct, end) != NULL) {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001810 end_len = parse_mbchar(end, NULL, NULL);
1811
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001812 while (end_len > 0) {
1813 *new_end = *end;
1814 new_end++;
1815 end++;
1816 end_len--;
1817 }
1818
1819 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001820 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001821
1822 while (end_len > 0) {
1823 *new_end = *end;
1824 new_end++;
1825 end++;
1826 end_len--;
1827 }
1828 }
1829
1830 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001831 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001832
1833 *new_end = ' ';
1834 new_end++;
1835 end += end_len;
1836 }
1837
1838 if (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001839 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001840
1841 *new_end = ' ';
1842 new_end++;
1843 end += end_len;
1844 }
1845
1846 while (*end != '\0' && is_blank_mbchar(end)) {
David Lawrence Ramsey96452cb2005-07-26 06:13:45 +00001847 end_len = parse_mbchar(end, NULL, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001848
1849 end += end_len;
1850 shift += end_len;
1851
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001852#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001853 /* Keep track of the change in the current line. */
1854 if (openfile->mark_set && openfile->mark_begin ==
1855 paragraph && openfile->mark_begin_x >= end -
1856 paragraph->data)
1857 mark_shift += end_len;
1858#endif
1859 }
1860 /* If this character is neither blank nor punctuation, leave it
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001861 * unchanged. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001862 } else {
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001863 end_len = parse_mbchar(end, NULL, NULL);
1864
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001865 while (end_len > 0) {
1866 *new_end = *end;
1867 new_end++;
1868 end++;
1869 end_len--;
1870 }
1871 }
1872 }
1873
1874 assert(*end == '\0');
1875
1876 *new_end = *end;
1877
David Lawrence Ramsey30bdadd2005-12-31 21:08:10 +00001878 /* If there are spaces at the end of the line, remove them. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001879 while (new_end > new_paragraph_data + skip &&
1880 *(new_end - 1) == ' ') {
1881 new_end--;
1882 shift++;
1883 }
1884
1885 if (shift > 0) {
1886 openfile->totsize -= shift;
1887 null_at(&new_paragraph_data, new_end - new_paragraph_data);
1888 free(paragraph->data);
1889 paragraph->data = new_paragraph_data;
1890
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00001891#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001892 /* Adjust the mark coordinates to compensate for the change in
1893 * the current line. */
1894 if (openfile->mark_set && openfile->mark_begin == paragraph) {
1895 openfile->mark_begin_x -= mark_shift;
1896 if (openfile->mark_begin_x > new_end - new_paragraph_data)
1897 openfile->mark_begin_x = new_end - new_paragraph_data;
1898 }
1899#endif
1900 } else
1901 free(new_paragraph_data);
1902}
1903
1904/* The "quote part" of a line is the largest initial substring matching
1905 * the quote string. This function returns the length of the quote part
1906 * of the given line.
1907 *
1908 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1909 * quotestr. */
1910size_t quote_length(const char *line)
1911{
1912#ifdef HAVE_REGEX_H
1913 regmatch_t matches;
1914 int rc = regexec(&quotereg, line, 1, &matches, 0);
1915
1916 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1917 return 0;
1918 /* matches.rm_so should be 0, since the quote string should start
1919 * with the caret ^. */
1920 return matches.rm_eo;
1921#else /* !HAVE_REGEX_H */
1922 size_t qdepth = 0;
1923
1924 /* Compute quote depth level. */
1925 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
1926 qdepth += quotelen;
1927 return qdepth;
1928#endif /* !HAVE_REGEX_H */
1929}
1930
1931/* a_line and b_line are lines of text. The quotation part of a_line is
1932 * the first a_quote characters. Check that the quotation part of
1933 * b_line is the same. */
1934bool quotes_match(const char *a_line, size_t a_quote, const char
1935 *b_line)
1936{
1937 /* Here is the assumption about a_quote. */
1938 assert(a_quote == quote_length(a_line));
1939
1940 return (a_quote == quote_length(b_line) &&
1941 strncmp(a_line, b_line, a_quote) == 0);
1942}
1943
1944/* We assume a_line and b_line have no quote part. Then, we return
1945 * whether b_line could follow a_line in a paragraph. */
1946bool indents_match(const char *a_line, size_t a_indent, const char
1947 *b_line, size_t b_indent)
1948{
1949 assert(a_indent == indent_length(a_line));
1950 assert(b_indent == indent_length(b_line));
1951
1952 return (b_indent <= a_indent &&
1953 strncmp(a_line, b_line, b_indent) == 0);
1954}
1955
1956/* Is foo the beginning of a paragraph?
1957 *
1958 * A line of text consists of a "quote part", followed by an
1959 * "indentation part", followed by text. The functions quote_length()
1960 * and indent_length() calculate these parts.
1961 *
1962 * A line is "part of a paragraph" if it has a part not in the quote
1963 * part or the indentation.
1964 *
1965 * A line is "the beginning of a paragraph" if it is part of a
1966 * paragraph and
1967 * 1) it is the top line of the file, or
1968 * 2) the line above it is not part of a paragraph, or
1969 * 3) the line above it does not have precisely the same quote
1970 * part, or
1971 * 4) the indentation of this line is not an initial substring of
1972 * the indentation of the previous line, or
1973 * 5) this line has no quote part and some indentation, and
1974 * autoindent isn't turned on.
1975 * The reason for number 5) is that if autoindent isn't turned on,
1976 * then an indented line is expected to start a paragraph, as in
1977 * books. Thus, nano can justify an indented paragraph only if
1978 * autoindent is turned on. */
1979bool begpar(const filestruct *const foo)
1980{
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001981 size_t quote_len, indent_len, temp_id_len;
1982
1983 if (foo == NULL)
1984 return FALSE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001985
1986 /* Case 1). */
David Lawrence Ramsey0083bd22005-11-09 18:26:44 +00001987 if (foo == openfile->fileage)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00001988 return TRUE;
1989
1990 quote_len = quote_length(foo->data);
1991 indent_len = indent_length(foo->data + quote_len);
1992
1993 /* Not part of a paragraph. */
1994 if (foo->data[quote_len + indent_len] == '\0')
1995 return FALSE;
1996
1997 /* Case 3). */
1998 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1999 return TRUE;
2000
2001 temp_id_len = indent_length(foo->prev->data + quote_len);
2002
2003 /* Case 2) or 5) or 4). */
2004 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
Benno Schulenberge4b8d6f2016-11-30 11:46:05 +01002005 (quote_len == 0 && indent_len > 0 && !ISSET(AUTOINDENT)) ||
2006 !indents_match(foo->prev->data + quote_len, temp_id_len,
2007 foo->data + quote_len, indent_len))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002008 return TRUE;
2009
2010 return FALSE;
2011}
2012
2013/* Is foo inside a paragraph? */
2014bool inpar(const filestruct *const foo)
2015{
2016 size_t quote_len;
2017
2018 if (foo == NULL)
2019 return FALSE;
2020
2021 quote_len = quote_length(foo->data);
2022
David Lawrence Ramsey21014032005-11-09 20:33:42 +00002023 return (foo->data[quote_len + indent_length(foo->data +
2024 quote_len)] != '\0');
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002025}
2026
David Lawrence Ramseyaf5a9992005-11-09 23:06:44 +00002027/* Move the next par_len lines, starting with first_line, into the
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00002028 * justify buffer, leaving copies of those lines in place. Assume that
2029 * par_len is greater than zero, and that there are enough lines after
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00002030 * first_line. */
2031void backup_lines(filestruct *first_line, size_t par_len)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002032{
2033 filestruct *top = first_line;
2034 /* The top of the paragraph we're backing up. */
2035 filestruct *bot = first_line;
2036 /* The bottom of the paragraph we're backing up. */
2037 size_t i;
2038 /* Generic loop variable. */
2039 size_t current_x_save = openfile->current_x;
2040 ssize_t fl_lineno_save = first_line->lineno;
2041 ssize_t edittop_lineno_save = openfile->edittop->lineno;
2042 ssize_t current_lineno_save = openfile->current->lineno;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002043#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002044 bool old_mark_set = openfile->mark_set;
2045 ssize_t mb_lineno_save = 0;
2046 size_t mark_begin_x_save = 0;
2047
2048 if (old_mark_set) {
2049 mb_lineno_save = openfile->mark_begin->lineno;
2050 mark_begin_x_save = openfile->mark_begin_x;
2051 }
2052#endif
2053
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00002054 /* par_len will be one greater than the number of lines between
2055 * current and filebot if filebot is the last line in the
2056 * paragraph. */
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00002057 assert(par_len > 0 && openfile->current->lineno + par_len <=
Benno Schulenberg95f417f2016-06-14 11:06:04 +02002058 openfile->filebot->lineno + 1);
David Lawrence Ramsey8bd960b2005-11-09 18:49:16 +00002059
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00002060 /* Move bot down par_len lines to the line after the last line of
2061 * the paragraph, if there is one. */
2062 for (i = par_len; i > 0 && bot != openfile->filebot; i--)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002063 bot = bot->next;
2064
2065 /* Move the paragraph from the current buffer's filestruct to the
2066 * justify buffer. */
David Lawrence Ramsey1cb945f2017-02-14 21:35:01 -06002067 extract_buffer(&jusbuffer, &jusbottom, top, 0, bot,
Benno Schulenberg95f417f2016-06-14 11:06:04 +02002068 (i == 1 && bot == openfile->filebot) ? strlen(bot->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002069
2070 /* Copy the paragraph back to the current buffer's filestruct from
2071 * the justify buffer. */
David Lawrence Ramsey1cb945f2017-02-14 21:35:01 -06002072 copy_from_buffer(jusbuffer);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002073
2074 /* Move upward from the last line of the paragraph to the first
2075 * line, putting first_line, edittop, current, and mark_begin at the
2076 * same lines in the copied paragraph that they had in the original
2077 * paragraph. */
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00002078 if (openfile->current != openfile->fileage) {
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00002079 top = openfile->current->prev;
David Lawrence Ramseyee43ea62007-04-22 15:04:05 +00002080#ifndef NANO_TINY
2081 if (old_mark_set &&
2082 openfile->current->lineno == mb_lineno_save) {
2083 openfile->mark_begin = openfile->current;
2084 openfile->mark_begin_x = mark_begin_x_save;
2085 }
2086#endif
2087 } else
David Lawrence Ramsey5c33e882005-11-09 18:58:04 +00002088 top = openfile->current;
David Lawrence Ramseye8d505b2005-11-10 03:40:45 +00002089 for (i = par_len; i > 0 && top != NULL; i--) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002090 if (top->lineno == fl_lineno_save)
2091 first_line = top;
2092 if (top->lineno == edittop_lineno_save)
2093 openfile->edittop = top;
2094 if (top->lineno == current_lineno_save)
2095 openfile->current = top;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002096#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002097 if (old_mark_set && top->lineno == mb_lineno_save) {
2098 openfile->mark_begin = top;
2099 openfile->mark_begin_x = mark_begin_x_save;
2100 }
2101#endif
2102 top = top->prev;
2103 }
2104
2105 /* Put current_x at the same place in the copied paragraph that it
2106 * had in the original paragraph. */
2107 openfile->current_x = current_x_save;
2108
2109 set_modified();
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002110}
2111
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002112/* Find the beginning of the current paragraph if we're in one, or the
2113 * beginning of the next paragraph if we're not. Afterwards, save the
2114 * quote length and paragraph length in *quote and *par. Return TRUE if
David Lawrence Ramsey139fa652006-05-22 01:26:24 +00002115 * we found a paragraph, and FALSE if there was an error or we didn't
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002116 * find a paragraph.
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002117 *
2118 * See the comment at begpar() for more about when a line is the
2119 * beginning of a paragraph. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002120bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002121{
2122 size_t quote_len;
2123 /* Length of the initial quotation of the paragraph we search
2124 * for. */
2125 size_t par_len;
2126 /* Number of lines in the paragraph we search for. */
2127 filestruct *current_save;
2128 /* The line at the beginning of the paragraph we search for. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002129
2130#ifdef HAVE_REGEX_H
2131 if (quoterc != 0) {
Benno Schulenberg2535f512016-04-30 17:31:43 +02002132 statusline(ALERT, _("Bad quote string %s: %s"), quotestr, quoteerr);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002133 return FALSE;
2134 }
2135#endif
2136
2137 assert(openfile->current != NULL);
2138
David Lawrence Ramsey1be131a2005-11-11 03:55:52 +00002139 /* If we're at the end of the last line of the file, it means that
2140 * there aren't any paragraphs left, so get out. */
2141 if (openfile->current == openfile->filebot && openfile->current_x ==
2142 strlen(openfile->filebot->data))
2143 return FALSE;
2144
2145 /* If the current line isn't in a paragraph, move forward to the
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00002146 * last line of the next paragraph, if any. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002147 if (!inpar(openfile->current)) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002148 do_para_end(FALSE);
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00002149
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00002150 /* If we end up past the beginning of the line, it means that
2151 * we're at the end of the last line of the file, and the line
2152 * isn't blank, in which case the last line of the file is the
2153 * last line of the next paragraph.
2154 *
2155 * Otherwise, if we end up on a line that's in a paragraph, it
2156 * means that we're on the line after the last line of the next
2157 * paragraph, in which case we should move back to the last line
2158 * of the next paragraph. */
2159 if (openfile->current_x == 0) {
2160 if (!inpar(openfile->current->prev))
2161 return FALSE;
2162 if (openfile->current != openfile->fileage)
2163 openfile->current = openfile->current->prev;
2164 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002165 }
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00002166
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00002167 /* If the current line isn't the first line of the paragraph, move
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002168 * back to the first line of the paragraph. */
2169 if (!begpar(openfile->current))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002170 do_para_begin(FALSE);
2171
2172 /* Now current is the first line of the paragraph. Set quote_len to
2173 * the quotation length of that line, and set par_len to the number
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00002174 * of lines in this paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002175 quote_len = quote_length(openfile->current->data);
2176 current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002177 do_para_end(FALSE);
2178 par_len = openfile->current->lineno - current_save->lineno;
David Lawrence Ramsey9a065c02005-11-29 18:25:53 +00002179
David Lawrence Ramseyd82dae02005-11-11 05:13:28 +00002180 /* If we end up past the beginning of the line, it means that we're
2181 * at the end of the last line of the file, and the line isn't
2182 * blank, in which case the last line of the file is part of the
2183 * paragraph. */
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00002184 if (openfile->current_x > 0)
2185 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002186 openfile->current = current_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002187
2188 /* Save the values of quote_len and par_len. */
2189 assert(quote != NULL && par != NULL);
2190
2191 *quote = quote_len;
2192 *par = par_len;
2193
2194 return TRUE;
2195}
2196
2197/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2198 * the current paragraph. */
2199void do_justify(bool full_justify)
2200{
2201 filestruct *first_par_line = NULL;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002202 /* Will be the first line of the justified paragraph(s), if any.
2203 * For restoring after unjustify. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002204 filestruct *last_par_line = NULL;
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002205 /* Will be the line after the last line of the justified
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002206 * paragraph(s), if any. Also for restoring after unjustify. */
David Lawrence Ramsey82b5deb2005-11-10 06:07:57 +00002207 bool filebot_inpar = FALSE;
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00002208 /* Whether the text at filebot is part of the current
2209 * paragraph. */
Benno Schulenberg97a5d122014-08-29 20:03:58 +00002210 int kbinput;
2211 /* The first keystroke after a justification. */
2212 functionptrtype func;
2213 /* The function associated with that keystroke. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002214
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00002215 /* We save these variables to be restored if the user
2216 * unjustifies. */
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00002217 filestruct *edittop_save = openfile->edittop;
2218 filestruct *current_save = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002219 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002220 size_t totsize_save = openfile->totsize;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002221#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002222 filestruct *mark_begin_save = openfile->mark_begin;
2223 size_t mark_begin_x_save = openfile->mark_begin_x;
2224#endif
David Lawrence Ramsey52161ee2005-11-10 19:56:26 +00002225 bool modified_save = openfile->modified;
2226
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002227 /* Move to the beginning of the current line, so that justifying at
David Lawrence Ramseybdff6652005-11-11 04:14:33 +00002228 * the end of the last line of the file, if that line isn't blank,
2229 * will work the first time through. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002230 openfile->current_x = 0;
2231
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002232 /* If we're justifying the entire file, start at the beginning. */
2233 if (full_justify)
2234 openfile->current = openfile->fileage;
2235
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002236 while (TRUE) {
2237 size_t i;
2238 /* Generic loop variable. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002239 filestruct *curr_first_par_line;
2240 /* The first line of the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002241 size_t quote_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002242 /* Length of the initial quotation of the current
2243 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002244 size_t indent_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002245 /* Length of the initial indentation of the current
2246 * paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002247 size_t par_len;
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002248 /* Number of lines in the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002249 ssize_t break_pos;
2250 /* Where we will break lines. */
2251 char *indent_string;
2252 /* The first indentation that doesn't match the initial
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002253 * indentation of the current paragraph. This is put at the
2254 * beginning of every line broken off the first justified
2255 * line of the paragraph. Note that this works because a
2256 * paragraph can only contain two indentations at most: the
2257 * initial one, and a different one starting on a line after
2258 * the first. See the comment at begpar() for more about
2259 * when a line is part of a paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002260
2261 /* Find the first line of the paragraph to be justified. That
2262 * is the start of this paragraph if we're in one, or the start
2263 * of the next otherwise. Save the quote length and paragraph
2264 * length (number of lines). Don't refresh the screen yet,
2265 * since we'll do that after we justify.
2266 *
2267 * If the search failed, we do one of two things. If we're
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00002268 * justifying the whole file, and we've found at least one
2269 * paragraph, it means that we should justify all the way to the
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002270 * last line of the file, so set the last line of the text to be
2271 * justified to the last line of the file and break out of the
2272 * loop. Otherwise, it means that there are no paragraph(s) to
2273 * justify, so refresh the screen and get out. */
David Lawrence Ramsey79383be2005-11-29 18:34:45 +00002274 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey8b203d62005-11-11 03:17:44 +00002275 if (full_justify && first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002276 last_par_line = openfile->filebot;
2277 break;
2278 } else {
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002279 refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002280 return;
2281 }
2282 }
2283
David Lawrence Ramseyb2d1c5f2005-11-10 06:01:41 +00002284 /* par_len will be one greater than the number of lines between
2285 * current and filebot if filebot is the last line in the
2286 * paragraph. Set filebot_inpar to TRUE if this is the case. */
2287 filebot_inpar = (openfile->current->lineno + par_len ==
2288 openfile->filebot->lineno + 1);
2289
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00002290 /* If we haven't already done it, move the original paragraph(s)
2291 * to the justify buffer, splice a copy of the original
2292 * paragraph(s) into the file in the same place, and set
2293 * first_par_line to the first line of the copy. */
2294 if (first_par_line == NULL) {
2295 backup_lines(openfile->current, full_justify ?
David Lawrence Ramsey53f641f2005-11-10 21:57:56 +00002296 openfile->filebot->lineno - openfile->current->lineno +
Benno Schulenberg964c10d2016-12-07 19:56:27 +01002297 ((openfile->filebot->data[0] != '\0') ? 1 : 0) : par_len);
David Lawrence Ramseycd8f7352005-11-10 21:20:32 +00002298 first_par_line = openfile->current;
2299 }
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002300
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002301 /* Set curr_first_par_line to the first line of the current
2302 * paragraph. */
2303 curr_first_par_line = openfile->current;
2304
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002305 /* Initialize indent_string to a blank string. */
2306 indent_string = mallocstrcpy(NULL, "");
2307
2308 /* Find the first indentation in the paragraph that doesn't
David Lawrence Ramsey8602fd62006-05-28 18:43:21 +00002309 * match the indentation of the first line, and save it in
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002310 * indent_string. If all the indentations are the same, save
2311 * the indentation of the first line in indent_string. */
2312 {
2313 const filestruct *indent_line = openfile->current;
2314 bool past_first_line = FALSE;
2315
2316 for (i = 0; i < par_len; i++) {
2317 indent_len = quote_len +
2318 indent_length(indent_line->data + quote_len);
2319
2320 if (indent_len != strlen(indent_string)) {
2321 indent_string = mallocstrncpy(indent_string,
2322 indent_line->data, indent_len + 1);
2323 indent_string[indent_len] = '\0';
2324
2325 if (past_first_line)
2326 break;
2327 }
2328
2329 if (indent_line == openfile->current)
2330 past_first_line = TRUE;
2331
2332 indent_line = indent_line->next;
2333 }
2334 }
2335
2336 /* Now tack all the lines of the paragraph together, skipping
2337 * the quoting and indentation on all lines after the first. */
2338 for (i = 0; i < par_len - 1; i++) {
2339 filestruct *next_line = openfile->current->next;
2340 size_t line_len = strlen(openfile->current->data);
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002341 size_t next_line_len = strlen(openfile->current->next->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002342
2343 indent_len = quote_len +
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002344 indent_length(openfile->current->next->data + quote_len);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002345
2346 next_line_len -= indent_len;
2347 openfile->totsize -= indent_len;
2348
2349 /* We're just about to tack the next line onto this one. If
2350 * this line isn't empty, make sure it ends in a space. */
Benno Schulenberg964c10d2016-12-07 19:56:27 +01002351 if (line_len > 0 && openfile->current->data[line_len - 1] != ' ') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002352 line_len++;
2353 openfile->current->data =
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002354 charealloc(openfile->current->data, line_len + 1);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002355 openfile->current->data[line_len - 1] = ' ';
2356 openfile->current->data[line_len] = '\0';
2357 openfile->totsize++;
2358 }
2359
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002360 openfile->current->data = charealloc(openfile->current->data,
2361 line_len + next_line_len + 1);
2362 strcat(openfile->current->data, next_line->data + indent_len);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002363
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002364#ifndef NANO_TINY
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002365 /* If needed, adjust the coordinates of the mark. */
Benno Schulenberg964c10d2016-12-07 19:56:27 +01002366 if (openfile->mark_set && openfile->mark_begin == next_line) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002367 openfile->mark_begin = openfile->current;
2368 openfile->mark_begin_x += line_len - indent_len;
2369 }
2370#endif
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002371 /* Don't destroy edittop! */
2372 if (next_line == openfile->edittop)
2373 openfile->edittop = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002374
2375 unlink_node(next_line);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002376
2377 /* If we've removed the next line, we need to go through
2378 * this line again. */
2379 i--;
2380
2381 par_len--;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002382 openfile->totsize--;
2383 }
2384
2385 /* Call justify_format() on the paragraph, which will remove
2386 * excess spaces from it and change all blank characters to
2387 * spaces. */
2388 justify_format(openfile->current, quote_len +
2389 indent_length(openfile->current->data + quote_len));
2390
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002391 while (par_len > 0 && strlenpt(openfile->current->data) > fill) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002392 size_t line_len = strlen(openfile->current->data);
2393
2394 indent_len = strlen(indent_string);
2395
2396 /* If this line is too long, try to wrap it to the next line
2397 * to make it short enough. */
David Lawrence Ramsey3f12ada2005-07-25 22:54:16 +00002398 break_pos = break_line(openfile->current->data + indent_len,
David Lawrence Ramseyb9b2fd52005-11-22 21:13:36 +00002399 fill - strnlenpt(openfile->current->data, indent_len)
2400#ifndef DISABLE_HELP
2401 , FALSE
2402#endif
2403 );
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002404
2405 /* We can't break the line, or don't need to, so get out. */
2406 if (break_pos == -1 || break_pos + indent_len == line_len)
2407 break;
2408
2409 /* Move forward to the character after the indentation and
2410 * just after the space. */
2411 break_pos += indent_len + 1;
2412
2413 assert(break_pos <= line_len);
2414
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002415 /* If this paragraph is non-quoted, and autoindent isn't
2416 * turned on, set the indentation length to zero so that the
2417 * indentation is treated as part of the line. */
Benno Schulenberge4b8d6f2016-11-30 11:46:05 +01002418 if (quote_len == 0 && !ISSET(AUTOINDENT))
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002419 indent_len = 0;
2420
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002421 /* Insert a new line after the current one. */
2422 splice_node(openfile->current, make_new_node(openfile->current));
2423
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002424 /* Copy the text after where we're going to break the
2425 * current line to the next line. */
2426 openfile->current->next->data = charalloc(indent_len + 1 +
2427 line_len - break_pos);
2428 strncpy(openfile->current->next->data, indent_string,
2429 indent_len);
2430 strcpy(openfile->current->next->data + indent_len,
2431 openfile->current->data + break_pos);
2432
2433 par_len++;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002434 openfile->totsize += indent_len + 1;
2435
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002436#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002437 /* Adjust the mark coordinates to compensate for the change
2438 * in the current line. */
Benno Schulenberg9a6f62f2015-12-08 19:09:14 +00002439 if (openfile->mark_set &&
2440 openfile->mark_begin == openfile->current &&
2441 openfile->mark_begin_x > break_pos) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002442 openfile->mark_begin = openfile->current->next;
2443 openfile->mark_begin_x -= break_pos - indent_len;
2444 }
2445#endif
2446
2447 /* Break the current line. */
Benno Schulenbergde3260c2017-02-22 17:24:10 +01002448 if (ISSET(JUSTIFY_TRIM)) {
Benno Schulenbergcdcd3652016-05-17 11:33:21 +02002449 while (break_pos > 0 &&
2450 is_blank_mbchar(&openfile->current->data[break_pos - 1])) {
Chris Allegretta16c037f2016-02-24 04:46:44 +00002451 break_pos--;
Benno Schulenbergde3260c2017-02-22 17:24:10 +01002452 openfile->totsize--;
Chris Allegretta16c037f2016-02-24 04:46:44 +00002453 }
2454 }
2455 null_at(&openfile->current->data, break_pos);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002456
2457 /* Go to the next line. */
2458 par_len--;
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002459 openfile->current = openfile->current->next;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002460 }
2461
2462 /* We're done breaking lines, so we don't need indent_string
2463 * anymore. */
2464 free(indent_string);
2465
David Lawrence Ramsey5455b6a2005-11-09 20:17:12 +00002466 /* Go to the next line, if possible. If there is no next line,
2467 * move to the end of the current line. */
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002468 if (openfile->current != openfile->filebot) {
David Lawrence Ramsey2c5d0ec2005-11-09 19:06:01 +00002469 openfile->current = openfile->current->next;
2470 } else
2471 openfile->current_x = strlen(openfile->current->data);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002472
Benno Schulenberg0f3e3032016-12-02 17:37:11 +01002473 /* Renumber the now-justified paragraph, since both refreshing the
2474 * edit window and finding a paragraph need correct line numbers. */
David Lawrence Ramseya6854682005-11-30 21:19:42 +00002475 renumber(curr_first_par_line);
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002476
2477 /* We've just finished justifying the paragraph. If we're not
2478 * justifying the entire file, break out of the loop.
2479 * Otherwise, continue the loop so that we justify all the
2480 * paragraphs in the file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002481 if (!full_justify)
2482 break;
2483 }
2484
2485 /* We are now done justifying the paragraph or the file, so clean
David Lawrence Ramseyb1c20622016-12-22 13:01:27 -06002486 * up. totsize has been maintained above. If we actually justified
2487 * something, set last_par_line to the new end of the paragraph. */
David Lawrence Ramseyad1b64c2005-11-29 19:00:09 +00002488 if (first_par_line != NULL)
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002489 last_par_line = openfile->current;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002490
2491 edit_refresh();
2492
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002493 /* Display the shortcut list with UnJustify. */
Benno Schulenbergbc6e9aa2014-04-07 09:02:22 +00002494 uncutfunc->desc = unjust_tag;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002495 display_main_list();
2496
2497 /* Now get a keystroke and see if it's unjustify. If not, put back
2498 * the keystroke and return. */
Benno Schulenberg75d64e62015-05-28 13:02:29 +00002499#ifndef NANO_TINY
2500 do {
2501#endif
2502 statusbar(_("Can now UnJustify!"));
Benno Schulenbergf45a2932016-03-29 14:09:17 +00002503 reset_cursor();
Benno Schulenberge085ebb2016-02-22 17:15:28 +00002504 curs_set(1);
Benno Schulenberg75d64e62015-05-28 13:02:29 +00002505 kbinput = do_input(FALSE);
2506#ifndef NANO_TINY
2507 } while (kbinput == KEY_WINCH);
2508#endif
2509
Benno Schulenberg158388c2016-06-16 20:40:09 +02002510 /* If needed, unset the cursor-position suppression flag, so the cursor
2511 * position /will/ be displayed upon a return to the main loop. */
2512 if (ISSET(CONST_UPDATE))
2513 do_cursorpos(TRUE);
2514
Benno Schulenberg97a5d122014-08-29 20:03:58 +00002515 func = func_from_key(&kbinput);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002516
Benno Schulenberg40e1fd32015-12-05 10:16:26 +00002517 if (func == do_uncut_text
2518#ifndef NANO_TINY
Benno Schulenberg17cf8332016-05-30 09:09:36 +02002519 || func == do_undo
Benno Schulenberg40e1fd32015-12-05 10:16:26 +00002520#endif
2521 ) {
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002522 /* If we actually justified something, then splice the preserved
2523 * unjustified text back into the file, */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002524 if (first_par_line != NULL) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002525 /* Partition the filestruct so that it contains only the
2526 * text of the justified paragraph. */
2527 filepart = partition_filestruct(first_par_line, 0,
Benno Schulenberg95f417f2016-06-14 11:06:04 +02002528 last_par_line, filebot_inpar ?
2529 strlen(last_par_line->data) : 0);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002530
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002531 /* Throw away the justified paragraph, and replace it with
2532 * the preserved unjustified text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002533 free_filestruct(openfile->fileage);
2534 openfile->fileage = jusbuffer;
2535 openfile->filebot = jusbottom;
2536
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002537 /* Unpartition the filestruct, to contain the entire text again. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002538 unpartition_filestruct(&filepart);
2539
Benno Schulenbergd9148e72016-10-12 19:20:39 +02002540 /* Renumber, from the beginning of the unjustified part. */
2541 renumber(jusbuffer);
2542
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002543 /* Restore the old position, the size, and the mark. */
David Lawrence Ramsey874ec8f2005-11-10 19:28:27 +00002544 openfile->edittop = edittop_save;
2545 openfile->current = current_save;
2546 openfile->current_x = current_x_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002547 openfile->totsize = totsize_save;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002548#ifndef NANO_TINY
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002549 if (openfile->mark_set) {
2550 openfile->mark_begin = mark_begin_save;
2551 openfile->mark_begin_x = mark_begin_x_save;
2552 }
2553#endif
2554 openfile->modified = modified_save;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002555 if (!openfile->modified)
2556 titlebar(NULL);
Benno Schulenbergd9148e72016-10-12 19:20:39 +02002557
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002558 refresh_needed = TRUE;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002559 }
2560 } else {
Benno Schulenberg8651fef2015-12-03 09:03:45 +00002561 /* Put the keystroke back into the queue. */
Benno Schulenberg91951ab2016-07-23 14:01:38 +02002562 unget_kbinput(kbinput, meta_key);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002563
Benno Schulenbergaa1ae0a2016-04-10 21:16:19 +02002564 /* Set the desired screen column (always zero, except at EOF). */
2565 openfile->placewewant = xplustabs();
2566
Benno Schulenberg40e1fd32015-12-05 10:16:26 +00002567#ifndef NANO_TINY
Benno Schulenberg8651fef2015-12-03 09:03:45 +00002568 /* Throw away the entire undo stack, to prevent a crash when
2569 * the user tries to undo something in the justified text. */
Benno Schulenbergf8459382016-01-15 16:44:50 +00002570 discard_until(NULL, openfile);
Benno Schulenberg40e1fd32015-12-05 10:16:26 +00002571#endif
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002572 /* Blow away the unjustified text. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002573 free_filestruct(jusbuffer);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002574 }
2575
Benno Schulenberg3264d0c2016-10-12 19:59:26 +02002576 /* Mark the buffer for unjustified text as empty. */
2577 jusbuffer = NULL;
2578
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002579 blank_statusbar();
2580
2581 /* Display the shortcut list with UnCut. */
Benno Schulenbergbc6e9aa2014-04-07 09:02:22 +00002582 uncutfunc->desc = uncut_tag;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002583 display_main_list();
2584}
2585
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002586/* Justify the current paragraph. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002587void do_justify_void(void)
2588{
2589 do_justify(FALSE);
2590}
2591
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002592/* Justify the entire file. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00002593void do_full_justify(void)
2594{
2595 do_justify(TRUE);
2596}
2597#endif /* !DISABLE_JUSTIFY */
2598
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002599#ifndef DISABLE_SPELLER
2600/* A word is misspelled in the file. Let the user replace it. We
2601 * return FALSE if the user cancels. */
2602bool do_int_spell_fix(const char *word)
2603{
Benno Schulenberg5022e472016-03-31 11:14:25 +00002604 char *save_search, *exp_word;
Benno Schulenberg5d1752c2016-04-04 17:53:26 +02002605 size_t current_x_save = openfile->current_x;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002606 filestruct *edittop_save = openfile->edittop;
2607 filestruct *current_save = openfile->current;
2608 /* Save where we are. */
Benno Schulenberg523bc0f2016-04-04 17:43:31 +02002609 bool proceed = FALSE;
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002610 /* The return value of this function. */
Benno Schulenberg5022e472016-03-31 11:14:25 +00002611 bool result;
2612 /* The return value of searching for a misspelled word. */
Benno Schulenberg583a30e2015-04-21 17:37:59 +00002613 unsigned stash[sizeof(flags) / sizeof(flags[0])];
2614 /* A storage place for the current flag settings. */
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002615#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002616 bool old_mark_set = openfile->mark_set;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002617 bool right_side_up = FALSE;
2618 /* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
2619 * FALSE if (current, current_x) is. */
2620 filestruct *top, *bot;
2621 size_t top_x, bot_x;
2622#endif
2623
Benno Schulenberg583a30e2015-04-21 17:37:59 +00002624 /* Save the settings of the global flags. */
2625 memcpy(stash, flags, sizeof(flags));
2626
Benno Schulenberg588daf92016-12-25 13:11:17 +01002627 /* Do the spell checking case sensitive, forward, and without regexes. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002628 SET(CASE_SENSITIVE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002629 UNSET(BACKWARDS_SEARCH);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002630 UNSET(USE_REGEXP);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002631
Benno Schulenberg51743232016-03-28 19:14:33 +00002632 /* Save the current search string, then set it to the misspelled word. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002633 save_search = last_search;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002634 last_search = mallocstrcpy(NULL, word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002635
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002636#ifndef NANO_TINY
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002637 /* If the mark is on, start at the beginning of the marked region. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002638 if (old_mark_set) {
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002639 mark_order((const filestruct **)&top, &top_x,
Benno Schulenberg95f417f2016-06-14 11:06:04 +02002640 (const filestruct **)&bot, &bot_x, &right_side_up);
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002641 /* If the region is marked normally, swap the end points, so that
2642 * (current, current_x) (where searching starts) is at the top. */
2643 if (right_side_up) {
2644 openfile->current = top;
Benno Schulenberg94e56322017-01-26 20:05:21 +01002645 openfile->current_x = top_x;
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002646 openfile->mark_begin = bot;
2647 openfile->mark_begin_x = bot_x;
Benno Schulenberg94e56322017-01-26 20:05:21 +01002648 }
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002649 openfile->mark_set = FALSE;
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002650 } else
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002651#endif
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002652 /* Otherwise, start from the top of the file. */
2653 {
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002654 openfile->current = openfile->fileage;
Benno Schulenberg94e56322017-01-26 20:05:21 +01002655 openfile->current_x = 0;
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002656 }
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002657
Benno Schulenberg5022e472016-03-31 11:14:25 +00002658 /* Find the first whole occurrence of word. */
Benno Schulenberg8f10e362017-02-10 13:51:51 +01002659 result = findnextstr(word, TRUE, TRUE, NULL, FALSE, NULL, 0);
Benno Schulenberg5022e472016-03-31 11:14:25 +00002660
Benno Schulenberg14ac4752016-08-03 12:50:56 +02002661 /* If the word isn't found, alert the user; if it is, allow correction. */
2662 if (result == 0) {
2663 statusline(ALERT, _("Unfindable word: %s"), word);
2664 lastmessage = HUSH;
2665 proceed = TRUE;
2666 napms(2800);
2667 } else if (result == 1) {
Benno Schulenberg5022e472016-03-31 11:14:25 +00002668 exp_word = display_string(openfile->current->data, xplustabs(),
Benno Schulenberg5d1752c2016-04-04 17:53:26 +02002669 strlenpt(word), FALSE);
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002670 edit_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002671
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002672 spotlight(TRUE, exp_word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002673
Benno Schulenberg5022e472016-03-31 11:14:25 +00002674 /* Let the user supply a correctly spelled alternative. */
Benno Schulenbergfd0589d2017-01-02 21:12:44 +01002675 proceed = (do_prompt(FALSE, FALSE, MSPELL, word,
Benno Schulenbergb341f292014-06-19 20:05:24 +00002676#ifndef DISABLE_HISTORIES
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002677 NULL,
David Lawrence Ramsey9d8c2842006-02-07 21:11:05 +00002678#endif
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002679 edit_refresh, _("Edit a replacement")) != -1);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002680
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002681 spotlight(FALSE, exp_word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002682
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002683 free(exp_word);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002684
Benno Schulenberg5022e472016-03-31 11:14:25 +00002685 /* If a replacement was given, go through all occurrences. */
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002686 if (proceed && strcmp(word, answer) != 0) {
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002687#ifndef NANO_TINY
2688 /* Replacements should happen only in the marked region. */
2689 openfile->mark_set = old_mark_set;
2690#endif
Benno Schulenberg2cd8ca42016-10-23 17:59:26 +02002691 do_replace_loop(word, TRUE, current_save, &current_x_save);
Benno Schulenbergbe4a3f82016-05-04 19:31:59 +02002692
2693 /* TRANSLATORS: Shown after fixing misspellings in one word. */
Benno Schulenbergf7c3e1c2016-05-18 10:25:16 +02002694 statusbar(_("Next word..."));
Benno Schulenbergbe4a3f82016-05-04 19:31:59 +02002695 napms(400);
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002696 }
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002697 }
2698
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002699#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002700 if (old_mark_set) {
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002701 /* Restore the (compensated) end points of the marked region. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002702 if (right_side_up) {
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002703 openfile->current = openfile->mark_begin;
2704 openfile->current_x = openfile->mark_begin_x;
2705 openfile->mark_begin = top;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002706 openfile->mark_begin_x = top_x;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002707 } else {
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002708 openfile->current = top;
2709 openfile->current_x = top_x;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002710 }
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002711 openfile->mark_set = TRUE;
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002712 } else
2713#endif
2714 {
2715 /* Restore the (compensated) cursor position. */
2716 openfile->current = current_save;
2717 openfile->current_x = current_x_save;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002718 }
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002719
Benno Schulenberg51743232016-03-28 19:14:33 +00002720 /* Restore the string that was last searched for. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002721 free(last_search);
2722 last_search = save_search;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002723
Benno Schulenberg433c7e52016-05-04 17:49:37 +02002724 /* Restore the viewport to where it was. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002725 openfile->edittop = edittop_save;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002726
Benno Schulenberg583a30e2015-04-21 17:37:59 +00002727 /* Restore the settings of the global flags. */
2728 memcpy(flags, stash, sizeof(flags));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002729
Benno Schulenberg06ea93b2016-03-31 11:27:16 +00002730 return proceed;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002731}
2732
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002733/* Internal (integrated) spell checking using the spell program,
2734 * filtered through the sort and uniq programs. Return NULL for normal
2735 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002736const char *do_int_speller(const char *tempfile_name)
2737{
2738 char *read_buff, *read_buff_ptr, *read_buff_word;
2739 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
2740 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
2741 pid_t pid_spell, pid_sort, pid_uniq;
2742 int spell_status, sort_status, uniq_status;
2743
2744 /* Create all three pipes up front. */
Benno Schulenbergc709c102016-03-30 12:30:14 +00002745 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002746 return _("Could not create pipe");
2747
2748 statusbar(_("Creating misspelled word list, please wait..."));
2749
2750 /* A new process to run spell in. */
2751 if ((pid_spell = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002752 /* Child continues (i.e. future spell process). */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002753 close(spell_fd[0]);
2754
2755 /* Replace the standard input with the temp file. */
2756 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
2757 goto close_pipes_and_exit;
2758
2759 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
2760 goto close_pipes_and_exit;
2761
2762 close(tempfile_fd);
2763
2764 /* Send spell's standard output to the pipe. */
2765 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2766 goto close_pipes_and_exit;
2767
2768 close(spell_fd[1]);
2769
David Lawrence Ramsey3239ff22005-11-29 20:01:06 +00002770 /* Start the spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002771 execlp("spell", "spell", NULL);
2772
2773 /* This should not be reached if spell is found. */
2774 exit(1);
2775 }
2776
2777 /* Parent continues here. */
2778 close(spell_fd[1]);
2779
2780 /* A new process to run sort in. */
2781 if ((pid_sort = fork()) == 0) {
Benno Schulenbergce48ca22015-04-08 19:57:31 +00002782 /* Child continues (i.e. future sort process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002783 * standard input with the standard output of the old pipe. */
2784 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
2785 goto close_pipes_and_exit;
2786
2787 close(spell_fd[0]);
2788
2789 /* Send sort's standard output to the new pipe. */
2790 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2791 goto close_pipes_and_exit;
2792
2793 close(sort_fd[1]);
2794
Benno Schulenbergce48ca22015-04-08 19:57:31 +00002795 /* Start the sort program. Use -f to ignore case. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002796 execlp("sort", "sort", "-f", NULL);
2797
2798 /* This should not be reached if sort is found. */
2799 exit(1);
2800 }
2801
2802 close(spell_fd[0]);
2803 close(sort_fd[1]);
2804
2805 /* A new process to run uniq in. */
2806 if ((pid_uniq = fork()) == 0) {
David Lawrence Ramseyb159f942006-07-28 17:06:27 +00002807 /* Child continues (i.e. future uniq process). Replace the
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002808 * standard input with the standard output of the old pipe. */
2809 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2810 goto close_pipes_and_exit;
2811
2812 close(sort_fd[0]);
2813
2814 /* Send uniq's standard output to the new pipe. */
2815 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2816 goto close_pipes_and_exit;
2817
2818 close(uniq_fd[1]);
2819
2820 /* Start the uniq program; we are using PATH. */
2821 execlp("uniq", "uniq", NULL);
2822
2823 /* This should not be reached if uniq is found. */
2824 exit(1);
2825 }
2826
2827 close(sort_fd[0]);
2828 close(uniq_fd[1]);
2829
2830 /* The child process was not forked successfully. */
2831 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2832 close(uniq_fd[0]);
2833 return _("Could not fork");
2834 }
2835
2836 /* Get the system pipe buffer size. */
2837 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2838 close(uniq_fd[0]);
2839 return _("Could not get size of pipe buffer");
2840 }
2841
2842 /* Read in the returned spelling errors. */
2843 read_buff_read = 0;
2844 read_buff_size = pipe_buff_size + 1;
2845 read_buff = read_buff_ptr = charalloc(read_buff_size);
2846
Benno Schulenbergc709c102016-03-30 12:30:14 +00002847 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002848 read_buff_read += bytesread;
2849 read_buff_size += pipe_buff_size;
Benno Schulenbergc709c102016-03-30 12:30:14 +00002850 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002851 read_buff_ptr += read_buff_read;
2852 }
2853
2854 *read_buff_ptr = '\0';
2855 close(uniq_fd[0]);
2856
2857 /* Process the spelling errors. */
2858 read_buff_word = read_buff_ptr = read_buff;
2859
2860 while (*read_buff_ptr != '\0') {
2861 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
2862 *read_buff_ptr = '\0';
2863 if (read_buff_word != read_buff_ptr) {
2864 if (!do_int_spell_fix(read_buff_word)) {
2865 read_buff_word = read_buff_ptr;
2866 break;
2867 }
2868 }
2869 read_buff_word = read_buff_ptr + 1;
2870 }
2871 read_buff_ptr++;
2872 }
2873
2874 /* Special case: the last word doesn't end with '\r' or '\n'. */
2875 if (read_buff_word != read_buff_ptr)
2876 do_int_spell_fix(read_buff_word);
2877
2878 free(read_buff);
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002879 search_replace_abort();
Benno Schulenberg53f4a9f2016-04-25 21:14:18 +02002880 refresh_needed = TRUE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002881
Benno Schulenbergce48ca22015-04-08 19:57:31 +00002882 /* Process the end of the three processes. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002883 waitpid(pid_spell, &spell_status, 0);
2884 waitpid(pid_sort, &sort_status, 0);
2885 waitpid(pid_uniq, &uniq_status, 0);
2886
2887 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2888 return _("Error invoking \"spell\"");
2889
Benno Schulenberg5bd359d2014-04-15 15:02:43 +00002890 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002891 return _("Error invoking \"sort -f\"");
2892
2893 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2894 return _("Error invoking \"uniq\"");
2895
Benno Schulenbergc709c102016-03-30 12:30:14 +00002896 /* When all went okay. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002897 return NULL;
2898
2899 close_pipes_and_exit:
2900 /* Don't leak any handles. */
2901 close(tempfile_fd);
2902 close(spell_fd[0]);
2903 close(spell_fd[1]);
2904 close(sort_fd[0]);
2905 close(sort_fd[1]);
2906 close(uniq_fd[0]);
2907 close(uniq_fd[1]);
2908 exit(1);
2909}
2910
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00002911/* External (alternate) spell checking. Return NULL for normal
2912 * termination, and the error string otherwise. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002913const char *do_alt_speller(char *tempfile_name)
2914{
2915 int alt_spell_status;
2916 size_t current_x_save = openfile->current_x;
Benno Schulenbergd8031af2016-08-11 18:24:59 +02002917 size_t pww_save = openfile->placewewant;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002918 ssize_t lineno_save = openfile->current->lineno;
Benno Schulenberg52d1c202015-03-17 20:10:59 +00002919 struct stat spellfileinfo;
Chris Allegrettaa0a05562015-03-23 04:32:45 +00002920 time_t timestamp;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002921 pid_t pid_spell;
2922 char *ptr;
2923 static int arglen = 3;
2924 static char **spellargs = NULL;
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002925#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002926 bool old_mark_set = openfile->mark_set;
Benno Schulenberg674ab832015-07-13 05:32:17 +00002927 bool added_magicline = FALSE;
2928 /* Whether we added a magicline after filebot. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002929 filestruct *top, *bot;
Benno Schulenbergd60e7d32017-02-16 11:44:04 +01002930 size_t top_x, bot_x, was_x, new_x;
Benno Schulenberg6f2da6b2015-03-27 20:16:36 +00002931 bool right_side_up = FALSE;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002932 ssize_t mb_lineno_save = 0;
2933 /* We're going to close the current file, and open the output of
2934 * the alternate spell command. The line that mark_begin points
2935 * to will be freed, so we save the line number and restore it
2936 * afterwards. */
Benno Schulenberg6039cd72015-07-17 21:11:32 +00002937 size_t size_of_surrounding = 0;
Benno Schulenbergaee86992015-07-12 19:27:26 +00002938 /* The size of the text outside of a marked region. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002939#endif
2940
Benno Schulenberg92142be2015-03-23 17:01:25 +00002941 /* Get the timestamp and the size of the temporary file. */
Benno Schulenberg52d1c202015-03-17 20:10:59 +00002942 stat(tempfile_name, &spellfileinfo);
2943 timestamp = spellfileinfo.st_mtime;
2944
Benno Schulenberg92142be2015-03-23 17:01:25 +00002945 /* If the number of bytes to check is zero, get out. */
2946 if (spellfileinfo.st_size == 0)
2947 return NULL;
2948
Benno Schulenberga37ebcf2015-03-23 17:12:49 +00002949#ifndef NANO_TINY
2950 if (old_mark_set) {
2951 /* If the mark is on, save the number of the line it starts on,
2952 * and then turn the mark off. */
2953 mb_lineno_save = openfile->mark_begin->lineno;
2954 openfile->mark_set = FALSE;
2955 }
2956#endif
2957
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002958 endwin();
2959
Benno Schulenbergce48ca22015-04-08 19:57:31 +00002960 /* Set up an argument list to pass to execvp(). */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002961 if (spellargs == NULL) {
2962 spellargs = (char **)nmalloc(arglen * sizeof(char *));
2963
2964 spellargs[0] = strtok(alt_speller, " ");
2965 while ((ptr = strtok(NULL, " ")) != NULL) {
2966 arglen++;
2967 spellargs = (char **)nrealloc(spellargs, arglen *
2968 sizeof(char *));
2969 spellargs[arglen - 3] = ptr;
2970 }
2971 spellargs[arglen - 1] = NULL;
2972 }
2973 spellargs[arglen - 2] = tempfile_name;
2974
2975 /* Start a new process for the alternate speller. */
2976 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey2e2112c2005-11-29 05:39:31 +00002977 /* Start alternate spell program; we are using $PATH. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002978 execvp(spellargs[0], spellargs);
2979
2980 /* Should not be reached, if alternate speller is found!!! */
2981 exit(1);
2982 }
2983
2984 /* If we couldn't fork, get out. */
2985 if (pid_spell < 0)
2986 return _("Could not fork");
2987
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00002988#ifndef NANO_TINY
Benno Schulenberg9e6b9a22016-01-04 10:37:11 +00002989 /* Block SIGWINCHes so the spell checker doesn't get any. */
2990 allow_sigwinch(FALSE);
David Lawrence Ramseyb18482e2005-07-26 00:06:34 +00002991#endif
2992
2993 /* Wait for the alternate spell checker to finish. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002994 wait(&alt_spell_status);
2995
David Lawrence Ramsey84fdb902005-08-14 20:08:49 +00002996 /* Reenter curses mode. */
2997 doupdate();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00002998
2999 /* Restore the terminal to its previous state. */
3000 terminal_init();
3001
Benno Schulenbergf2259912015-04-17 09:24:17 +00003002 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003003#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003004 /* Turn the mark back on if it was on before. */
3005 openfile->mark_set = old_mark_set;
3006#endif
Benno Schulenbergf2259912015-04-17 09:24:17 +00003007 return invocation_error(alt_speller);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003008 }
3009
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003010#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003011 if (old_mark_set) {
Benno Schulenberg74e75212015-07-18 10:32:01 +00003012 /* Trim the filestruct so that it contains only the marked text. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003013 mark_order((const filestruct **)&top, &top_x,
Benno Schulenberg95f417f2016-06-14 11:06:04 +02003014 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003015 filepart = partition_filestruct(top, top_x, bot, bot_x);
Benno Schulenberg74e75212015-07-18 10:32:01 +00003016
3017 /* Foresay whether a magicline will be added when the
3018 * spell-checked text is read back in. */
Benno Schulenberg674ab832015-07-13 05:32:17 +00003019 if (!ISSET(NO_NEWLINES))
3020 added_magicline = (openfile->filebot->data[0] != '\0');
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003021
Benno Schulenbergaee86992015-07-12 19:27:26 +00003022 /* Compute the size of the text outside of the marked region. */
3023 size_of_surrounding = openfile->totsize - get_totsize(top, bot);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003024 }
3025#endif
3026
Benno Schulenberg17cf8332016-05-30 09:09:36 +02003027 /* Replace the text of the current buffer with the spell-checked text. */
David Lawrence Ramsey9c984e82005-11-08 19:15:58 +00003028 replace_buffer(tempfile_name);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003029
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003030#ifndef NANO_TINY
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003031 if (old_mark_set) {
3032 filestruct *top_save = openfile->fileage;
Benno Schulenberg13ec5d82016-12-10 13:20:06 +01003033
3034 /* If a magicline was added, remove it again. */
3035 if (added_magicline)
3036 remove_magicline();
3037
Benno Schulenberg6f2da6b2015-03-27 20:16:36 +00003038 /* Adjust the end point of the marked region for any change in
Benno Schulenberg17cf8332016-05-30 09:09:36 +02003039 * length of the region's last line. */
Benno Schulenberg6f2da6b2015-03-27 20:16:36 +00003040 if (right_side_up)
Benno Schulenbergd60e7d32017-02-16 11:44:04 +01003041 was_x = current_x_save;
Benno Schulenberg6f2da6b2015-03-27 20:16:36 +00003042 else
Benno Schulenbergd60e7d32017-02-16 11:44:04 +01003043 was_x = openfile->mark_begin_x;
3044 if (top == bot)
3045 new_x = was_x - bot_x + top_x + strlen(openfile->filebot->data);
3046 else
3047 new_x = strlen(openfile->filebot->data);
3048 if (right_side_up)
3049 current_x_save = new_x;
3050 else
3051 openfile->mark_begin_x = new_x;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003052
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003053 /* Unpartition the filestruct so that it contains all the text
3054 * again. Note that we've replaced the marked text originally
3055 * in the partition with the spell-checked marked text in the
3056 * temp file. */
3057 unpartition_filestruct(&filepart);
3058
Benno Schulenbergaee86992015-07-12 19:27:26 +00003059 /* Renumber, starting with the beginning line of the old partition. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003060 renumber(top_save);
Benno Schulenbergaee86992015-07-12 19:27:26 +00003061
3062 /* Add back the size of the text surrounding the marked region. */
3063 openfile->totsize += size_of_surrounding;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003064
Benno Schulenberg6007d622015-11-22 16:08:28 +00003065 /* Restore the position of the mark, and turn it back on. */
Benno Schulenberg6f2da6b2015-03-27 20:16:36 +00003066 openfile->mark_begin = fsfromline(mb_lineno_save);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003067 openfile->mark_set = TRUE;
3068 }
Benno Schulenberg953ccc92015-06-28 14:12:25 +00003069#endif /* !NANO_TINY */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003070
Benno Schulenberg52d1c202015-03-17 20:10:59 +00003071 /* Go back to the old position. */
Benno Schulenberg82d737e2015-03-21 21:02:13 +00003072 goto_line_posx(lineno_save, current_x_save);
Benno Schulenbergedbc1e52016-12-24 12:09:47 +01003073 if (openfile->current_x > strlen(openfile->current->data))
3074 openfile->current_x = strlen(openfile->current->data);
Benno Schulenbergd8031af2016-08-11 18:24:59 +02003075 openfile->placewewant = pww_save;
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02003076 adjust_viewport(STATIONARY);
Benno Schulenberg52d1c202015-03-17 20:10:59 +00003077
3078 /* Stat the temporary file again, and mark the buffer as modified only
3079 * if this file was changed since it was written. */
3080 stat(tempfile_name, &spellfileinfo);
Benno Schulenbergd21a9c82016-12-23 22:12:48 +01003081 if (spellfileinfo.st_mtime != timestamp) {
Benno Schulenberg52d1c202015-03-17 20:10:59 +00003082 set_modified();
Felix Jandafc89ac12016-12-29 13:43:06 -05003083#ifndef NANO_TINY
Benno Schulenbergd21a9c82016-12-23 22:12:48 +01003084 /* Flush the undo stack, to avoid making a mess when the user
3085 * tries to undo things in spell-corrected lines. */
3086 discard_until(NULL, openfile);
Felix Jandafc89ac12016-12-29 13:43:06 -05003087#endif
Benno Schulenbergd21a9c82016-12-23 22:12:48 +01003088 }
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003089#ifndef NANO_TINY
Benno Schulenberg9e6b9a22016-01-04 10:37:11 +00003090 /* Unblock SIGWINCHes again. */
3091 allow_sigwinch(TRUE);
David Lawrence Ramsey3fe08ac2005-07-26 01:17:16 +00003092#endif
3093
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003094 return NULL;
3095}
3096
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003097/* Spell check the current file. If an alternate spell checker is
3098 * specified, use it. Otherwise, use the internal spell checker. */
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003099void do_spell(void)
3100{
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00003101 bool status;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003102 FILE *temp_file;
Benno Schulenberg9eca1952016-01-02 16:01:04 +00003103 char *temp;
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003104 const char *spell_msg;
3105
Chris Allegrettaab538642010-11-12 06:22:12 +00003106 if (ISSET(RESTRICTED)) {
Benno Schulenberg68476162015-07-30 18:10:16 +00003107 show_restricted_warning();
Chris Allegrettaab538642010-11-12 06:22:12 +00003108 return;
3109 }
3110
Benno Schulenberg9eca1952016-01-02 16:01:04 +00003111 temp = safe_tempfile(&temp_file);
3112
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003113 if (temp == NULL) {
Benno Schulenberg24b10172016-06-27 09:27:49 +02003114 statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003115 return;
3116 }
3117
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003118#ifndef NANO_TINY
Benno Schulenberg21edf7b2016-05-08 13:03:47 +02003119 if (openfile->mark_set)
3120 status = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
3121 else
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003122#endif
Benno Schulenberg21edf7b2016-05-08 13:03:47 +02003123 status = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003124
David Lawrence Ramsey9e7b2d52007-01-11 22:46:22 +00003125 if (!status) {
Benno Schulenberg24b10172016-06-27 09:27:49 +02003126 statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003127 free(temp);
3128 return;
3129 }
3130
Benno Schulenberg85c2c2a2014-05-12 11:50:58 +00003131 blank_bottombars();
3132 statusbar(_("Invoking spell checker, please wait"));
Benno Schulenberg85c2c2a2014-05-12 11:50:58 +00003133
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003134 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
Benno Schulenberg21edf7b2016-05-08 13:03:47 +02003135 do_int_speller(temp);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003136 unlink(temp);
3137 free(temp);
3138
3139 /* If the spell-checker printed any error messages onscreen, make
3140 * sure that they're cleared off. */
David Lawrence Ramseyf32e1dd2006-06-09 17:09:51 +00003141 total_refresh();
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003142
3143 if (spell_msg != NULL) {
3144 if (errno == 0)
3145 /* Don't display an error message of "Success". */
Benno Schulenberg2535f512016-04-30 17:31:43 +02003146 statusline(ALERT, _("Spell checking failed: %s"), spell_msg);
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003147 else
Benno Schulenberg2535f512016-04-30 17:31:43 +02003148 statusline(ALERT, _("Spell checking failed: %s: %s"), spell_msg,
Benno Schulenberg21edf7b2016-05-08 13:03:47 +02003149 strerror(errno));
David Lawrence Ramseycc8185f2005-07-25 02:33:45 +00003150 } else
3151 statusbar(_("Finished checking spelling"));
3152}
3153#endif /* !DISABLE_SPELLER */
3154
Benno Schulenberg00389922014-04-04 11:59:03 +00003155#ifndef DISABLE_COLOR
Benno Schulenberg0dd351a2016-01-04 10:05:52 +00003156/* Run a linting program on the current buffer. Return NULL for normal
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003157 * termination, and the error string otherwise. */
3158void do_linter(void)
3159{
3160 char *read_buff, *read_buff_ptr, *read_buff_word, *ptr;
3161 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
3162 size_t parsesuccess = 0;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003163 int lint_status, lint_fd[2];
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003164 pid_t pid_lint;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003165 static int arglen = 3;
3166 static char **lintargs = NULL;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003167 char *lintcopy, *convendptr = NULL;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003168 lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL;
3169
Benno Schulenberge4294a22015-07-29 17:36:39 +00003170 if (ISSET(RESTRICTED)) {
Benno Schulenberg68476162015-07-30 18:10:16 +00003171 show_restricted_warning();
3172 return;
Benno Schulenberge4294a22015-07-29 17:36:39 +00003173 }
3174
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003175 if (!openfile->syntax || !openfile->syntax->linter) {
Benno Schulenberg127ce152014-05-13 08:12:52 +00003176 statusbar(_("No linter defined for this type of file!"));
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003177 return;
3178 }
3179
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003180 if (openfile->modified) {
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003181 int i = do_yesno_prompt(FALSE, _("Save modified buffer before linting?"));
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003182
Chris Allegretta61523be2014-05-11 03:09:00 +00003183 if (i == -1) {
3184 statusbar(_("Cancelled"));
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003185 return;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003186 } else if (i == 1 && (do_writeout(FALSE) != TRUE))
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003187 return;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003188 }
3189
3190 lintcopy = mallocstrcpy(NULL, openfile->syntax->linter);
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003191 /* Create a pipe up front. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003192 if (pipe(lint_fd) == -1) {
3193 statusbar(_("Could not create pipe"));
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003194 return;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003195 }
3196
Chris Allegretta61523be2014-05-11 03:09:00 +00003197 blank_bottombars();
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003198 statusbar(_("Invoking linter, please wait"));
3199
Benno Schulenbergce48ca22015-04-08 19:57:31 +00003200 /* Set up an argument list to pass to execvp(). */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003201 if (lintargs == NULL) {
3202 lintargs = (char **)nmalloc(arglen * sizeof(char *));
3203
3204 lintargs[0] = strtok(lintcopy, " ");
3205 while ((ptr = strtok(NULL, " ")) != NULL) {
3206 arglen++;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003207 lintargs = (char **)nrealloc(lintargs, arglen * sizeof(char *));
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003208 lintargs[arglen - 3] = ptr;
3209 }
3210 lintargs[arglen - 1] = NULL;
3211 }
3212 lintargs[arglen - 2] = openfile->filename;
3213
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003214 /* Start a new process to run the linter in. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003215 if ((pid_lint = fork()) == 0) {
3216
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003217 /* Child continues here (i.e. the future linting process). */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003218 close(lint_fd[0]);
3219
Benno Schulenbergce48ca22015-04-08 19:57:31 +00003220 /* Send the linter's standard output + err to the pipe. */
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003221 if (dup2(lint_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
Benno Schulenbergf2259912015-04-17 09:24:17 +00003222 exit(9);
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003223 if (dup2(lint_fd[1], STDERR_FILENO) != STDERR_FILENO)
Benno Schulenbergf2259912015-04-17 09:24:17 +00003224 exit(9);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003225
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003226 close(lint_fd[1]);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003227
3228 /* Start the linter program; we are using $PATH. */
3229 execvp(lintargs[0], lintargs);
3230
Benno Schulenbergf2259912015-04-17 09:24:17 +00003231 /* This is only reached when the linter is not found. */
3232 exit(9);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003233 }
3234
3235 /* Parent continues here. */
3236 close(lint_fd[1]);
3237
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003238 /* If the child process was not forked successfully... */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003239 if (pid_lint < 0) {
3240 close(lint_fd[0]);
3241 statusbar(_("Could not fork"));
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003242 return;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003243 }
3244
3245 /* Get the system pipe buffer size. */
3246 if ((pipe_buff_size = fpathconf(lint_fd[0], _PC_PIPE_BUF)) < 1) {
3247 close(lint_fd[0]);
Benno Schulenberga65ef422014-03-17 21:36:37 +00003248 statusbar(_("Could not get size of pipe buffer"));
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003249 return;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003250 }
3251
Benno Schulenbergce48ca22015-04-08 19:57:31 +00003252 /* Read in the returned syntax errors. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003253 read_buff_read = 0;
3254 read_buff_size = pipe_buff_size + 1;
3255 read_buff = read_buff_ptr = charalloc(read_buff_size);
3256
Benno Schulenbergc709c102016-03-30 12:30:14 +00003257 while ((bytesread = read(lint_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003258#ifdef DEBUG
Benno Schulenbergacda2552014-06-09 15:08:59 +00003259 fprintf(stderr, "text.c:do_linter:%ld bytes (%s)\n", (long)bytesread, read_buff_ptr);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003260#endif
3261 read_buff_read += bytesread;
3262 read_buff_size += pipe_buff_size;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003263 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003264 read_buff_ptr += read_buff_read;
3265 }
3266
3267 *read_buff_ptr = '\0';
3268 close(lint_fd[0]);
3269
3270#ifdef DEBUG
3271 fprintf(stderr, "text.c:do_lint:Raw output: %s\n", read_buff);
3272#endif
3273
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003274 /* Process the linter output. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003275 read_buff_word = read_buff_ptr = read_buff;
3276
3277 while (*read_buff_ptr != '\0') {
3278 if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
3279 *read_buff_ptr = '\0';
3280 if (read_buff_word != read_buff_ptr) {
3281 char *filename = NULL, *linestr = NULL, *maybecol = NULL;
3282 char *message = mallocstrcpy(NULL, read_buff_word);
3283
3284 /* At the moment we're assuming the following formats:
Benno Schulenbergd19be5a2014-04-08 18:38:45 +00003285 *
3286 * filenameorcategory:line:column:message (e.g. splint)
3287 * filenameorcategory:line:message (e.g. pyflakes)
3288 * filenameorcategory:line,col:message (e.g. pylint)
3289 *
3290 * This could be turned into some scanf() based parser,
3291 * but ugh. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003292 if ((filename = strtok(read_buff_word, ":")) != NULL) {
3293 if ((linestr = strtok(NULL, ":")) != NULL) {
3294 if ((maybecol = strtok(NULL, ":")) != NULL) {
3295 ssize_t tmplineno = 0, tmpcolno = 0;
3296 char *tmplinecol;
3297
3298 tmplineno = strtol(linestr, NULL, 10);
3299 if (tmplineno <= 0) {
3300 read_buff_ptr++;
3301 free(message);
3302 continue;
3303 }
3304
Benno Schulenberg52e35332014-05-16 11:03:04 +00003305 tmpcolno = strtol(maybecol, &convendptr, 10);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003306 if (*convendptr != '\0') {
Benno Schulenbergd19be5a2014-04-08 18:38:45 +00003307 /* Previous field might still be
3308 * line,col format. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003309 strtok(linestr, ",");
3310 if ((tmplinecol = strtok(NULL, ",")) != NULL)
3311 tmpcolno = strtol(tmplinecol, NULL, 10);
3312 }
3313
3314#ifdef DEBUG
Benno Schulenbergacda2552014-06-09 15:08:59 +00003315 fprintf(stderr, "text.c:do_lint:Successful parse! %ld:%ld:%s\n", (long)tmplineno, (long)tmpcolno, message);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003316#endif
Benno Schulenbergd19be5a2014-04-08 18:38:45 +00003317 /* Nice. We have a lint message we can use. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003318 parsesuccess++;
3319 tmplint = curlint;
3320 curlint = nmalloc(sizeof(lintstruct));
3321 curlint->next = NULL;
3322 curlint->prev = tmplint;
3323 if (curlint->prev != NULL)
3324 curlint->prev->next = curlint;
3325 curlint->msg = mallocstrcpy(NULL, message);
3326 curlint->lineno = tmplineno;
3327 curlint->colno = tmpcolno;
3328 curlint->filename = mallocstrcpy(NULL, filename);
3329
3330 if (lints == NULL)
3331 lints = curlint;
3332 }
3333 }
3334 } else
3335 free(message);
3336 }
3337 read_buff_word = read_buff_ptr + 1;
3338 }
3339 read_buff_ptr++;
3340 }
3341
Benno Schulenbergf2259912015-04-17 09:24:17 +00003342 /* Process the end of the linting process. */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003343 waitpid(pid_lint, &lint_status, 0);
3344
Benno Schulenbergf2259912015-04-17 09:24:17 +00003345 if (!WIFEXITED(lint_status) || WEXITSTATUS(lint_status) > 2) {
3346 statusbar(invocation_error(openfile->syntax->linter));
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003347 return;
Benno Schulenbergf2259912015-04-17 09:24:17 +00003348 }
3349
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003350 free(read_buff);
3351
3352 if (parsesuccess == 0) {
Benno Schulenberg2535f512016-04-30 17:31:43 +02003353 statusline(HUSH, _("Got 0 parsable lines from command: %s"),
3354 openfile->syntax->linter);
Benno Schulenberg9106cc82016-05-08 12:01:33 +02003355 return;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003356 }
3357
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003358 bottombars(MLINTER);
3359 tmplint = NULL;
3360 curlint = lints;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003361
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003362 while (TRUE) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003363 int kbinput;
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003364 functionptrtype func;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003365
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003366 if (tmplint != curlint) {
Benno Schulenbergb8b29ff2014-04-03 21:06:30 +00003367#ifndef NANO_TINY
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003368 struct stat lintfileinfo;
3369
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003370 new_lint_loop:
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003371 if (stat(curlint->filename, &lintfileinfo) != -1) {
3372 if (openfile->current_stat->st_ino != lintfileinfo.st_ino) {
3373 openfilestruct *tmpof = openfile;
3374 while (tmpof != openfile->next) {
3375 if (tmpof->current_stat->st_ino == lintfileinfo.st_ino)
3376 break;
3377 tmpof = tmpof->next;
3378 }
3379 if (tmpof->current_stat->st_ino != lintfileinfo.st_ino) {
3380 char *msg = charalloc(1024 + strlen(curlint->filename));
3381 int i;
3382
Benno Schulenberg568d2a32016-02-13 19:41:12 +00003383 sprintf(msg, _("This message is for unopened file %s,"
3384 " open it in a new buffer?"),
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003385 curlint->filename);
3386 i = do_yesno_prompt(FALSE, msg);
3387 free(msg);
Chris Allegretta61523be2014-05-11 03:09:00 +00003388 if (i == -1) {
3389 statusbar(_("Cancelled"));
3390 goto free_lints_and_return;
3391 } else if (i == 1) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003392 SET(MULTIBUFFER);
3393 open_buffer(curlint->filename, FALSE);
3394 } else {
3395 char *dontwantfile = curlint->filename;
3396
3397 while (curlint != NULL && !strcmp(curlint->filename, dontwantfile))
3398 curlint = curlint->next;
3399 if (curlint == NULL) {
Benno Schulenberg9d72efa2016-01-04 11:10:07 +00003400 statusbar(_("No more errors in unopened files, cancelling"));
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003401 break;
3402 } else
3403 goto new_lint_loop;
3404 }
3405 } else
3406 openfile = tmpof;
3407 }
3408 }
Benno Schulenberge4c34c32014-03-17 14:15:57 +00003409#endif /* !NANO_TINY */
Benno Schulenberg6a002f52016-02-22 19:49:45 +00003410 do_gotolinecolumn(curlint->lineno, curlint->colno, FALSE, FALSE);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003411 titlebar(NULL);
3412 edit_refresh();
3413 statusbar(curlint->msg);
3414 bottombars(MLINTER);
3415 }
3416
Benno Schulenberg79e3eaf2016-06-21 16:10:16 +02003417 /* Place and show the cursor to indicate the affected line. */
Benno Schulenberg7dd10302016-02-22 18:34:04 +00003418 reset_cursor();
Benno Schulenberg79e3eaf2016-06-21 16:10:16 +02003419 wnoutrefresh(edit);
Benno Schulenberg568d2a32016-02-13 19:41:12 +00003420 curs_set(1);
3421
Benno Schulenberg7e5324d2014-06-30 18:04:33 +00003422 kbinput = get_kbinput(bottomwin);
Benno Schulenberg75d64e62015-05-28 13:02:29 +00003423
3424#ifndef NANO_TINY
3425 if (kbinput == KEY_WINCH)
3426 continue;
3427#endif
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003428 func = func_from_key(&kbinput);
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003429 tmplint = curlint;
3430
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003431 if (func == do_cancel)
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003432 break;
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003433 else if (func == do_help_void) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003434 tmplint = NULL;
3435 do_help_void();
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003436 } else if (func == do_page_down) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003437 if (curlint->next != NULL)
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003438 curlint = curlint->next;
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003439 else
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003440 statusbar(_("At last message"));
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003441 } else if (func == do_page_up) {
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003442 if (curlint->prev != NULL)
3443 curlint = curlint->prev;
Benno Schulenberg47dffa42014-07-27 20:16:28 +00003444 else
Benno Schulenberga9fdfd02014-07-16 08:53:16 +00003445 statusbar(_("At first message"));
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003446 }
3447 }
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003448
Chris Allegretta61523be2014-05-11 03:09:00 +00003449 blank_statusbar();
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003450
Benno Schulenbergc3c2c662014-05-26 07:53:20 +00003451#ifndef NANO_TINY
Benno Schulenberg953ccc92015-06-28 14:12:25 +00003452 free_lints_and_return:
Benno Schulenbergc3c2c662014-05-26 07:53:20 +00003453#endif
Benno Schulenbergd4118ef2016-02-11 08:50:11 +00003454 for (curlint = lints; curlint != NULL;) {
3455 tmplint = curlint;
3456 curlint = curlint->next;
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003457 free(tmplint->msg);
3458 free(tmplint->filename);
3459 free(tmplint);
3460 }
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003461}
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003462
Benno Schulenberg14a9c8a2015-03-27 16:55:49 +00003463#ifndef DISABLE_SPELLER
Benno Schulenbergce48ca22015-04-08 19:57:31 +00003464/* Run a formatter for the current syntax. This expects the formatter
3465 * to be non-interactive and operate on a file in-place, which we'll
3466 * pass it on the command line. */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003467void do_formatter(void)
3468{
3469 bool status;
3470 FILE *temp_file;
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003471 int format_status;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003472 ssize_t lineno_save = openfile->current->lineno;
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003473 size_t current_x_save = openfile->current_x;
3474 size_t pww_save = openfile->placewewant;
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003475 pid_t pid_format;
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003476 static int arglen = 3;
3477 static char **formatargs = NULL;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003478 char *temp, *ptr, *finalstatus = NULL;
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003479
Benno Schulenberg9eca1952016-01-02 16:01:04 +00003480 if (openfile->totsize == 0) {
3481 statusbar(_("Finished"));
3482 return;
3483 }
3484
3485 temp = safe_tempfile(&temp_file);
3486
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003487 if (temp == NULL) {
Benno Schulenberg2535f512016-04-30 17:31:43 +02003488 statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003489 return;
3490 }
3491
Benno Schulenberg69d26c32015-03-14 20:17:21 +00003492 /* We're not supporting partial formatting, oi vey. */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003493 openfile->mark_set = FALSE;
3494 status = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE);
3495
3496 if (!status) {
Benno Schulenberg2535f512016-04-30 17:31:43 +02003497 statusline(ALERT, _("Error writing temp file: %s"), strerror(errno));
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003498 free(temp);
3499 return;
3500 }
3501
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003502 blank_bottombars();
3503 statusbar(_("Invoking formatter, please wait"));
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003504
Benno Schulenbergce48ca22015-04-08 19:57:31 +00003505 /* Set up an argument list to pass to execvp(). */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003506 if (formatargs == NULL) {
3507 formatargs = (char **)nmalloc(arglen * sizeof(char *));
3508
3509 formatargs[0] = strtok(openfile->syntax->formatter, " ");
3510 while ((ptr = strtok(NULL, " ")) != NULL) {
3511 arglen++;
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003512 formatargs = (char **)nrealloc(formatargs, arglen * sizeof(char *));
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003513 formatargs[arglen - 3] = ptr;
3514 }
3515 formatargs[arglen - 1] = NULL;
3516 }
3517 formatargs[arglen - 2] = temp;
3518
3519 /* Start a new process for the formatter. */
3520 if ((pid_format = fork()) == 0) {
Benno Schulenberg69d26c32015-03-14 20:17:21 +00003521 /* Start the formatting program; we are using $PATH. */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003522 execvp(formatargs[0], formatargs);
3523
Benno Schulenberg69d26c32015-03-14 20:17:21 +00003524 /* Should not be reached, if the formatter is found! */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003525 exit(1);
3526 }
3527
3528 /* If we couldn't fork, get out. */
3529 if (pid_format < 0) {
3530 statusbar(_("Could not fork"));
Benno Schulenberg9eca1952016-01-02 16:01:04 +00003531 unlink(temp);
3532 free(temp);
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003533 return;
3534 }
3535
3536#ifndef NANO_TINY
Benno Schulenberg9e6b9a22016-01-04 10:37:11 +00003537 /* Block SIGWINCHes so the formatter doesn't get any. */
3538 allow_sigwinch(FALSE);
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003539#endif
3540
3541 /* Wait for the formatter to finish. */
3542 wait(&format_status);
3543
Benno Schulenbergf2259912015-04-17 09:24:17 +00003544 if (!WIFEXITED(format_status) || WEXITSTATUS(format_status) != 0)
3545 finalstatus = invocation_error(openfile->syntax->formatter);
3546 else {
Benno Schulenberg69d26c32015-03-14 20:17:21 +00003547 /* Replace the text of the current buffer with the formatted text. */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003548 replace_buffer(temp);
3549
Benno Schulenbergedbc1e52016-12-24 12:09:47 +01003550 /* Restore the cursor position. */
Benno Schulenberg33bc96a2015-12-31 16:44:32 +00003551 goto_line_posx(lineno_save, current_x_save);
Benno Schulenbergedbc1e52016-12-24 12:09:47 +01003552 if (openfile->current_x > strlen(openfile->current->data))
3553 openfile->current_x = strlen(openfile->current->data);
Benno Schulenberg33bc96a2015-12-31 16:44:32 +00003554 openfile->placewewant = pww_save;
Benno Schulenberg01bbf7e2016-10-20 21:11:11 +02003555 adjust_viewport(STATIONARY);
Benno Schulenberg33bc96a2015-12-31 16:44:32 +00003556
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003557 set_modified();
3558
Benno Schulenbergd21a9c82016-12-23 22:12:48 +01003559 /* Flush the undo stack, to avoid a mess or crash when
3560 * the user tries to undo things in reformatted lines. */
3561 discard_until(NULL, openfile);
3562
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003563 finalstatus = _("Finished formatting");
3564 }
3565
3566 unlink(temp);
3567 free(temp);
3568
Benno Schulenbergbff6a902015-07-28 19:39:34 +00003569#ifndef NANO_TINY
Benno Schulenberg9e6b9a22016-01-04 10:37:11 +00003570 /* Unblock SIGWINCHes again. */
3571 allow_sigwinch(TRUE);
Benno Schulenbergbff6a902015-07-28 19:39:34 +00003572#endif
3573
Benno Schulenberge39938c2016-02-11 16:57:52 +00003574 statusbar(finalstatus);
3575
3576 /* If there were error messages, allow the user some time to read them. */
3577 if (WIFEXITED(format_status) && WEXITSTATUS(format_status) == 2)
3578 sleep(4);
3579
Benno Schulenbergde5b2632016-02-11 17:25:37 +00003580 /* If there were any messages, clear them off. */
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003581 total_refresh();
Chris Allegretta4b3f2772015-01-03 07:24:17 +00003582}
Benno Schulenberg14a9c8a2015-03-27 16:55:49 +00003583#endif /* !DISABLE_SPELLER */
Benno Schulenberg00389922014-04-04 11:59:03 +00003584#endif /* !DISABLE_COLOR */
Chris Allegretta5575bfa2014-02-24 10:18:15 +00003585
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003586#ifndef NANO_TINY
David Lawrence Ramseyd7f0fe92005-08-10 22:51:49 +00003587/* Our own version of "wc". Note that its character counts are in
3588 * multibyte characters instead of single-byte characters. */
David Lawrence Ramsey8e942342005-07-25 04:21:46 +00003589void do_wordlinechar_count(void)
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003590{
David Lawrence Ramsey520a90c2005-07-25 21:23:11 +00003591 size_t words = 0, chars = 0;
Chris Allegretta8b6461f2008-05-31 23:09:40 +00003592 ssize_t nlines = 0;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003593 size_t current_x_save = openfile->current_x;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003594 size_t pww_save = openfile->placewewant;
3595 filestruct *current_save = openfile->current;
3596 bool old_mark_set = openfile->mark_set;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003597 filestruct *top, *bot;
3598 size_t top_x, bot_x;
3599
Benno Schulenberg74e75212015-07-18 10:32:01 +00003600 /* If the mark is on, partition the filestruct so that it
3601 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003602 if (old_mark_set) {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003603 mark_order((const filestruct **)&top, &top_x,
Benno Schulenberg95f417f2016-06-14 11:06:04 +02003604 (const filestruct **)&bot, &bot_x, NULL);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003605 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003606 openfile->mark_set = FALSE;
3607 }
3608
3609 /* Start at the top of the file. */
3610 openfile->current = openfile->fileage;
3611 openfile->current_x = 0;
3612 openfile->placewewant = 0;
3613
3614 /* Keep moving to the next word (counting punctuation characters as
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003615 * part of a word, as "wc -w" does), without updating the screen,
3616 * until we reach the end of the file, incrementing the total word
3617 * count whenever we're on a word just before moving. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003618 while (openfile->current != openfile->filebot ||
David Lawrence Ramsey2ffdea42005-11-03 21:08:39 +00003619 openfile->current->data[openfile->current_x] != '\0') {
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003620 if (do_next_word(TRUE, FALSE))
3621 words++;
3622 }
3623
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003624 /* Get the total line and character counts, as "wc -l" and "wc -c"
3625 * do, but get the latter in multibyte characters. */
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003626 if (old_mark_set) {
Benno Schulenberg74e75212015-07-18 10:32:01 +00003627 nlines = openfile->filebot->lineno - openfile->fileage->lineno + 1;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003628 chars = get_totsize(openfile->fileage, openfile->filebot);
3629
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003630 /* Unpartition the filestruct so that it contains all the text
3631 * again, and turn the mark back on. */
3632 unpartition_filestruct(&filepart);
3633 openfile->mark_set = TRUE;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003634 } else {
Chris Allegretta8b6461f2008-05-31 23:09:40 +00003635 nlines = openfile->filebot->lineno;
David Lawrence Ramsey72936852005-07-25 03:47:08 +00003636 chars = openfile->totsize;
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003637 }
3638
3639 /* Restore where we were. */
3640 openfile->current = current_save;
3641 openfile->current_x = current_x_save;
3642 openfile->placewewant = pww_save;
3643
Benno Schulenberg74e75212015-07-18 10:32:01 +00003644 /* Display the total word, line, and character counts on the statusbar. */
Benno Schulenberg2535f512016-04-30 17:31:43 +02003645 statusline(HUSH, _("%sWords: %lu Lines: %ld Chars: %lu"), old_mark_set ?
3646 _("In Selection: ") : "", (unsigned long)words, (long)nlines,
3647 (unsigned long)chars);
David Lawrence Ramsey691698a2005-07-24 19:57:51 +00003648}
David Lawrence Ramseyebe34252005-11-15 03:17:35 +00003649#endif /* !NANO_TINY */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003650
David Lawrence Ramsey6d6a36c2005-12-08 07:09:08 +00003651/* Get verbatim input. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003652void do_verbatim_input(void)
3653{
3654 int *kbinput;
3655 size_t kbinput_len, i;
3656 char *output;
3657
David Lawrence Ramseyf451d6a2006-05-27 16:02:48 +00003658 /* TRANSLATORS: This is displayed when the next keystroke will be
3659 * inserted verbatim. */
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003660 statusbar(_("Verbatim Input"));
Benno Schulenbergf45a2932016-03-29 14:09:17 +00003661 reset_cursor();
3662 curs_set(1);
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003663
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003664 /* Read in all the verbatim characters. */
3665 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
3666
David Lawrence Ramseya620e682006-05-27 18:19:03 +00003667 /* If constant cursor position display is on, make sure the current
3668 * cursor position will be properly displayed on the statusbar.
3669 * Otherwise, blank the statusbar. */
3670 if (ISSET(CONST_UPDATE))
3671 do_cursorpos(TRUE);
3672 else {
3673 blank_statusbar();
3674 wnoutrefresh(bottomwin);
3675 }
David Lawrence Ramsey6fb66892006-05-27 17:39:19 +00003676
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003677 /* Display all the verbatim characters at once, not filtering out
3678 * control characters. */
3679 output = charalloc(kbinput_len + 1);
3680
3681 for (i = 0; i < kbinput_len; i++)
3682 output[i] = (char)kbinput[i];
3683 output[i] = '\0';
3684
David Lawrence Ramseyad36bdc2006-12-02 17:22:21 +00003685 free(kbinput);
3686
David Lawrence Ramsey37ddfa92005-11-07 06:06:05 +00003687 do_output(output, kbinput_len, TRUE);
3688
3689 free(output);
3690}
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303691
Benno Schulenberg68a03142016-12-07 13:10:40 +01003692#ifdef ENABLE_WORDCOMPLETION
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303693/* Copy the found completion candidate. */
3694char *copy_completion(char *check_line, int start)
3695{
3696 char *word;
3697 int position = start, len_of_word = 0, index = 0;
3698
3699 /* Find the length of the word by travelling to its end. */
3700 while (is_word_mbchar(&check_line[position], FALSE)) {
3701 int next = move_mbright(check_line, position);
3702 len_of_word += next - position;
3703 position = next;
3704 }
3705
3706 word = (char *)nmalloc((len_of_word + 1) * sizeof(char));
3707
3708 /* Simply copy the word. */
3709 while (index < len_of_word)
3710 word[index++] = check_line[start++];
3711
3712 word[index] = '\0';
3713 return word;
3714}
3715
3716/* Look at the fragment the user has typed, then search the current buffer for
3717 * the first word that starts with this fragment, and tentatively complete the
3718 * fragment. If the user types 'Complete' again, search and paste the next
3719 * possible completion. */
3720void complete_a_word(void)
3721{
3722 char *shard, *completion = NULL;
3723 int start_of_shard, shard_length = 0;
3724 int i = 0, j = 0;
3725 completion_word *some_word;
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003726#ifndef DISABLE_WRAPPING
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303727 bool was_set_wrapping = !ISSET(NO_WRAP);
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003728#endif
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303729
3730 /* If this is a fresh completion attempt... */
3731 if (pletion_line == NULL) {
3732 /* Clear the list of words of a previous completion run. */
3733 while (list_of_completions != NULL) {
3734 completion_word *dropit = list_of_completions;
3735 list_of_completions = list_of_completions->next;
3736 free(dropit->word);
3737 free(dropit);
3738 }
3739
3740 /* Prevent a completion from being merged with typed text. */
3741 openfile->last_action = OTHER;
3742
3743 /* Initialize the starting point for searching. */
3744 pletion_line = openfile->fileage;
3745 pletion_x = 0;
3746
3747 /* Wipe the "No further matches" message. */
3748 blank_statusbar();
3749 wnoutrefresh(bottomwin);
3750 } else {
3751 /* Remove the attempted completion from the buffer. */
3752 do_undo();
3753 }
3754
3755 /* Find the start of the fragment that the user typed. */
3756 start_of_shard = openfile->current_x;
3757 while (start_of_shard > 0) {
3758 int step_left = move_mbleft(openfile->current->data, start_of_shard);
3759
3760 if (!is_word_mbchar(&openfile->current->data[step_left], FALSE))
3761 break;
3762 start_of_shard = step_left;
3763 }
3764
3765 /* If there is no word fragment before the cursor, do nothing. */
3766 if (start_of_shard == openfile->current_x) {
3767 pletion_line = NULL;
3768 return;
3769 }
3770
3771 shard = (char *)nmalloc((openfile->current_x - start_of_shard + 1) * sizeof(char));
3772
3773 /* Copy the fragment that has to be searched for. */
3774 while (start_of_shard < openfile->current_x)
3775 shard[shard_length++] = openfile->current->data[start_of_shard++];
3776 shard[shard_length] = '\0';
3777
3778 /* Run through all of the lines in the buffer, looking for shard. */
3779 while (pletion_line != NULL) {
3780 int threshold = strlen(pletion_line->data) - shard_length - 1;
3781 /* The point where we can stop searching for shard. */
3782
3783 /* Traverse the whole line, looking for shard. */
3784 for (i = pletion_x; i < threshold; i++) {
3785 /* If the first byte doesn't match, run on. */
3786 if (pletion_line->data[i] != shard[0])
3787 continue;
3788
3789 /* Compare the rest of the bytes in shard. */
3790 for (j = 1; j < shard_length; j++)
3791 if (pletion_line->data[i + j] != shard[j])
3792 break;
3793
3794 /* If not all of the bytes matched, continue searching. */
3795 if (j < shard_length)
3796 continue;
3797
3798 /* If the found match is not /longer/ than shard, skip it. */
3799 if (!is_word_mbchar(&pletion_line->data[i + j], FALSE))
3800 continue;
3801
3802 /* If the match is not a separate word, skip it. */
3803 if (i > 0 && is_word_mbchar(&pletion_line->data[
3804 move_mbleft(pletion_line->data, i)], FALSE))
3805 continue;
3806
3807 /* If this match is the shard itself, ignore it. */
3808 if (pletion_line == openfile->current &&
3809 i == openfile->current_x - shard_length)
3810 continue;
3811
3812 completion = copy_completion(pletion_line->data, i);
3813
3814 /* Look among earlier attempted completions for a duplicate. */
3815 some_word = list_of_completions;
3816 while (some_word && strcmp(some_word->word, completion) != 0)
3817 some_word = some_word->next;
3818
3819 /* If we've already tried this word, skip it. */
3820 if (some_word != NULL) {
3821 free(completion);
3822 continue;
3823 }
3824
3825 /* Add the found word to the list of completions. */
3826 some_word = (completion_word *)nmalloc(sizeof(completion_word));
3827 some_word->word = completion;
3828 some_word->next = list_of_completions;
3829 list_of_completions = some_word;
3830
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003831#ifndef DISABLE_WRAPPING
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303832 /* Temporarily disable wrapping so only one undo item is added. */
3833 SET(NO_WRAP);
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003834#endif
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303835 /* Inject the completion into the buffer. */
3836 do_output(&completion[shard_length],
3837 strlen(completion) - shard_length, FALSE);
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003838#ifndef DISABLE_WRAPPING
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303839 /* If needed, reenable wrapping and wrap the current line. */
3840 if (was_set_wrapping) {
3841 UNSET(NO_WRAP);
3842 do_wrap(openfile->current);
3843 }
Benno Schulenberg7373e4c2017-01-01 16:33:40 +01003844#endif
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303845 /* Set the position for a possible next search attempt. */
3846 pletion_x = ++i;
3847
3848 free(shard);
3849 return;
3850 }
3851
3852 pletion_line = pletion_line->next;
3853 pletion_x = 0;
3854 }
3855
3856 /* The search has reached the end of the file. */
3857 if (list_of_completions != NULL) {
3858 statusline(ALERT, _("No further matches"));
3859 refresh_needed = TRUE;
3860 } else
Benno Schulenberg173bbe12016-12-07 20:56:28 +01003861 /* TRANSLATORS: Shown when there are zero possible completions. */
Sumedh Pendurkardca4ab52016-12-07 09:43:47 +05303862 statusline(ALERT, _("No matches"));
3863
3864 free(shard);
3865}
Benno Schulenberg68a03142016-12-07 13:10:40 +01003866#endif /* ENABLE_WORDCOMPLETION */