add code to partition a filestruct between a set of arbitrary

coordinates; given the coordinates of the beginning and end of the mark,
this allows proper and easier handling of saving marked selections,
replacing text only in marked selections, and spell-checking marked
selections using either the internal or alternate spell checker; do all
these using a global partition structure


git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2050 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
master
David Lawrence Ramsey 2004-11-03 22:03:41 +00:00
parent 29f03dcff9
commit 40bdb686aa
9 changed files with 358 additions and 74 deletions

View File

@ -93,6 +93,18 @@ CVS code -
some functions that use them as a parameter to use size_t as
well. Also change some related assertions to handle them.
(David Benbennick and DLR)
- Add code to partition a filestruct between a set of arbitrary
coordinates. Given the coordinates of the beginning and end
of the mark, this allows proper and easier handling of saving
marked selections, replacing text only in marked selections
(suggested by Joseph Birthisel), and spell-checking marked
selections using either the internal or alternate spell
checker. Do all these using a global partition structure.
New functions partition_filestruct(),
unpartition_filestruct(), remove_magicline(), and
get_totals(); changes to write_marked(), do_int_spell_fix(),
do_alt_speller(), handle_sigwinch(), and do_replace_loop().
(DLR)
- files.c:
do_insertfile()
- Simplify by reusing variables whereever possible, and add a

3
TODO
View File

@ -10,8 +10,7 @@ For version 1.4:
- Rebindable keys?
- Keystroke to implement "Add next sequence as raw" like vi's ^V.
[DONE for edit window, needs to be done for statusbar prompt]
- Spell check selected text only. [DONE for internal spell checker,
partially done for external spell checker]
- Spell check selected text only. [DONE]
- Make "To Line" (^W^T) and "Read from Command" (^R^X) reenter their
parent menu when their keystroke is entered a second time (^W^T^T and
(^R^X^X) (requires figuring out when to keep cursor position and when

View File

@ -1720,49 +1720,36 @@ int write_file(const char *name, int tmp, int append, int nonamechange)
int write_marked(const char *name, int tmp, int append)
{
int retval = -1;
filestruct *fileagebak = fileage;
filestruct *filebotbak = filebot;
bool old_modified = ISSET(MODIFIED);
/* write_file() unsets the MODIFIED flag. */
size_t topx;
/* The column of the beginning of the mark. */
char origchar;
/* We replace the character at the end of the mark with '\0'.
* We save the original character, to restore it. */
char *origcharloc;
/* The location of the character we nulled. */
bool added_magicline;
/* Whether we added a magicline after filebot. */
filestruct *top, *bot;
size_t top_x, bot_x;
/* Set fileage as the top of the mark, and filebot as the bottom. */
if (current->lineno > mark_beginbuf->lineno ||
(current->lineno == mark_beginbuf->lineno &&
current_x > mark_beginx)) {
fileage = mark_beginbuf;
topx = mark_beginx;
filebot = current;
origcharloc = current->data + current_x;
} else {
fileage = current;
topx = current_x;
filebot = mark_beginbuf;
origcharloc = mark_beginbuf->data + mark_beginx;
}
origchar = *origcharloc;
*origcharloc = '\0';
fileage->data += topx;
/* Partition the filestruct so that it contains only the marked
* text. */
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x);
filepart = partition_filestruct(top, top_x, bot, bot_x);
/* If the line at filebot is blank, treat it as the magicline and
* hence the end of the file. Otherwise, treat the line after
* filebot as the end of the file. */
if (filebot->data[0] != '\0' && filebot->next != NULL)
filebot = filebot->next;
* hence the end of the file. Otherwise, add a magicline and treat
* it as the end of the file. */
added_magicline = (filebot->data[0] != '\0');
if (added_magicline)
new_magicline();
retval = write_file(name, tmp, append, TRUE);
/* Now restore everything. */
fileage->data -= topx;
*origcharloc = origchar;
fileage = fileagebak;
filebot = filebotbak;
/* If we added a magicline, remove it now. */
if (added_magicline)
remove_magicline();
/* Unpartition the filestruct so that it contains all the text
* again. */
unpartition_filestruct(filepart);
if (old_modified)
set_modified();

View File

@ -63,6 +63,11 @@ filestruct *edittop = NULL; /* Pointer to the top of the edit
filestruct *filebot = NULL; /* Last node in the file struct */
filestruct *cutbuffer = NULL; /* A place to store cut text */
#ifndef NANO_SMALL
partition *filepart = NULL; /* A place to store a portion of the
file struct */
#endif
#ifdef ENABLE_MULTIBUFFER
openfilestruct *open_files = NULL; /* The list of open files */
#endif

View File

@ -616,6 +616,93 @@ void free_filestruct(filestruct *src)
}
}
#ifndef NANO_SMALL
/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
* bot_x). */
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x)
{
partition *p;
assert(top != NULL && bot != NULL);
/* Initialize the partition. */
p = (partition *)nmalloc(sizeof(partition));
/* Save the top and bottom of the filestruct. */
p->fileage = fileage;
p->filebot = filebot;
/* Set the top and bottom of the partition to top and bot. */
fileage = top;
filebot = bot;
/* Save the line above the top of the partition, detach the top of
* the partition from it, and save the text before top_x in
* top_data. */
p->top_prev = top->prev;
top->prev = NULL;
p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
p->top_data[top_x] = '\0';
/* Save the line below the bottom of the partition, detach the
* bottom of the partition from it, and save the text after bot_x in
* bot_data. */
p->bot_next = bot->next;
bot->next = NULL;
p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
/* Remove all text after bot_x at the bottom of the partition. */
null_at(&bot->data, bot_x);
/* Remove all text before top_x at the top of the partition. */
charmove(top->data, top->data + top_x, strlen(top->data) -
top_x + 1);
align(&top->data);
/* Return the partition. */
return p;
}
/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
* (filebot, strlen(filebot)) again. */
void unpartition_filestruct(partition *p)
{
char *tmp;
assert(p != NULL);
/* Reattach the line above the top of the partition, and restore the
* text before top_x from top_data. Free top_data when we're done
* with it. */
tmp = mallocstrcpy(NULL, fileage->data);
fileage->prev = p->top_prev;
fileage->prev->next = fileage;
fileage->data = charealloc(fileage->data, strlen(p->top_data) +
strlen(fileage->data) + 1);
strcpy(fileage->data, p->top_data);
free(p->top_data);
strcat(fileage->data, tmp);
free(tmp);
/* Reattach the line below the bottom of the partition, and restore
* the text after bot_x from bot_data. Free bot_data when we're
* done with it. */
filebot->next = p->bot_next;
filebot->next->prev = filebot;
filebot->data = charealloc(filebot->data, strlen(filebot->data) +
strlen(p->bot_data) + 1);
strcat(filebot->data, p->bot_data);
free(p->bot_data);
/* Restore the top and bottom of the filestruct. */
fileage = p->fileage;
filebot = p->filebot;
/* Uninitialize the partition. */
free(p);
p = NULL;
}
#endif
void renumber_all(void)
{
filestruct *temp;
@ -1442,6 +1529,8 @@ bool do_int_spell_fix(const char *word)
#endif
#ifndef NANO_SMALL
bool old_mark_set = ISSET(MARK_ISSET);
filestruct *top, *bot;
size_t top_x, bot_x;
#endif
/* Make sure spell-check is case sensitive. */
@ -1455,10 +1544,6 @@ bool do_int_spell_fix(const char *word)
/* Make sure spell-check doesn't use regular expressions. */
UNSET(USE_REGEXP);
#endif
#ifndef NANO_SMALL
/* Make sure the marking highlight is off during spell-check. */
UNSET(MARK_ISSET);
#endif
/* Save the current search/replace strings. */
search_init_globals();
@ -1469,6 +1554,16 @@ bool do_int_spell_fix(const char *word)
last_search = mallocstrcpy(NULL, word);
last_replace = mallocstrcpy(NULL, word);
#ifndef NANO_SMALL
if (old_mark_set) {
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x);
filepart = partition_filestruct(top, top_x, bot, bot_x);
edittop = fileage;
UNSET(MARK_ISSET);
}
#endif
/* Start from the top of the file. */
edittop = fileage;
current = fileage;
@ -1493,9 +1588,17 @@ bool do_int_spell_fix(const char *word)
do_replace_highlight(FALSE, word);
if (!canceled && strcmp(word, answer) != 0) {
bool added_magicline = (filebot->data[0] != '\0');
/* Whether we added a magicline after
* filebot. */
current_x--;
do_replace_loop(word, current, &current_x, TRUE,
&canceled);
/* If we added a magicline, remove it now. */
if (added_magicline)
remove_magicline();
}
break;
@ -1508,6 +1611,15 @@ bool do_int_spell_fix(const char *word)
free(last_replace);
last_replace = save_replace;
#ifndef NANO_SMALL
/* If the mark was on, unpartition the filestruct so that it
* contains all the text again, and turn the mark back on. */
if (old_mark_set) {
unpartition_filestruct(filepart);
SET(MARK_ISSET);
}
#endif
/* Restore where we were. */
edittop = edittop_save;
current = current_save;
@ -1528,11 +1640,6 @@ bool do_int_spell_fix(const char *word)
if (regexp_set)
SET(USE_REGEXP);
#endif
#ifndef NANO_SMALL
/* Restore marking highlight. */
if (old_mark_set)
SET(MARK_ISSET);
#endif
return !canceled;
}
@ -1737,13 +1844,23 @@ const char *do_alt_speller(char *tempfile_name)
FILE *f;
#ifndef NANO_SMALL
bool old_mark_set = ISSET(MARK_ISSET);
bool added_magicline = FALSE;
/* Whether we added a magicline after filebot. */
int mbb_lineno_cur = 0;
/* We're going to close the current file, and open the output of
* the alternate spell command. The line that mark_beginbuf
* points to will be freed, so we save the line number and
* restore afterwards. */
int old_totlines = totlines;
/* Our saved value of totlines, used when we spell-check a
* marked selection. */
long old_totsize = totsize;
/* Our saved value of totsize, used when we spell-check a marked
* selection. */
if (old_mark_set) {
/* If the mark is on, save the number of the line it starts on,
* and then turn the mark off. */
mbb_lineno_cur = mark_beginbuf->lineno;
UNSET(MARK_ISSET);
}
@ -1798,24 +1915,77 @@ const char *do_alt_speller(char *tempfile_name)
#ifndef NANO_SMALL
if (old_mark_set) {
do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
mark_beginbuf = current;
/* In case the line got shorter, assign mark_beginx. */
mark_beginx = current_x;
SET(MARK_ISSET);
} else {
filestruct *top, *bot;
size_t top_x, bot_x;
int part_totlines;
long part_totsize;
/* If the mark was on, partition the filestruct so that it
* contains only the marked text, and keep track of whether the
* temp file (which should contain the spell-checked marked
* text) will have a magicline added when it's reloaded. */
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x);
filepart = partition_filestruct(top, top_x, bot, bot_x);
added_magicline = (filebot->data[0] != '\0');
/* Get the number of lines and the number of characters in the
* marked text, and subtract them from the saved values of
* totlines and totsize. */
get_totals(top, bot, &part_totlines, &part_totsize);
old_totlines -= part_totlines;
old_totsize -= part_totsize;
}
#endif
/* Only reload the temp file if it isn't a marked selection. */
/* Reinitialize the filestruct. */
free_filestruct(fileage);
global_init(TRUE);
/* Do what load_buffer() would do, except for making a new
* buffer for the temp file if multibuffer support is
/* Reload the temp file. Do what load_buffer() would do, except for
* making a new buffer for the temp file if multibuffer support is
* available. */
open_file(tempfile_name, FALSE, &f);
read_file(f, tempfile_name);
current = fileage;
#ifndef NANO_SMALL
if (old_mark_set) {
filestruct *old_top = fileage;
/* If we added a magicline, remove it now. */
if (added_magicline)
remove_magicline();
/* If the mark was on, unpartition the filestruct so that it
* contains all the text again. Note that we've replaced the
* marked text originally in the partition with the
* spell-checked marked text in the temp file. */
unpartition_filestruct(filepart);
/* Renumber starting with the beginning line of the old
* partition. Also add the number of lines and characters in
* the spell-checked marked text to the saved values of totlines
* and totsize, and then make those saved values the actual
* values. */
renumber(old_top);
old_totlines += totlines;
old_totsize += totsize;
totlines = old_totlines;
totsize = old_totsize;
/* Assign mark_beginbuf to the line where the mark began
* before. */
do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
mark_beginbuf = current;
/* Assign mark_beginx to the location in mark_beginbuf where the
* mark began before, adjusted for any shortening of the
* line. */
mark_beginx = current_x;
/* Turn the mark back on. */
SET(MARK_ISSET);
}
#endif
@ -2845,6 +3015,10 @@ void handle_sigwinch(int s)
memset(hblank, ' ', COLS);
hblank[COLS] = '\0';
/* If we've partitioned the filestruct, unpartition it now. */
if (filepart != NULL)
unpartition_filestruct(filepart);
#ifdef USE_SLANG
/* Slang curses emulation brain damage, part 1: If we just do what
* curses does here, it'll only work properly if the resize made the

View File

@ -183,6 +183,17 @@ typedef struct openfilestruct {
} openfilestruct;
#endif
#ifndef NANO_SMALL
typedef struct partition {
filestruct *fileage;
filestruct *top_prev;
char *top_data;
filestruct *filebot;
filestruct *bot_next;
char *bot_data;
} partition;
#endif
typedef struct shortcut {
/* Key values that aren't used should be set to NANO_NO_KEY. */
int ctrlval; /* Special sentinel key or control key we want

View File

@ -87,6 +87,7 @@ extern struct stat fileinfo;
extern filestruct *current, *fileage, *edittop, *filebot;
extern filestruct *cutbuffer;
#ifndef NANO_SMALL
extern partition *filepart;
extern filestruct *mark_beginbuf;
#endif
@ -301,6 +302,11 @@ void unlink_node(const filestruct *fileptr);
void delete_node(filestruct *fileptr);
filestruct *copy_filestruct(const filestruct *src);
void free_filestruct(filestruct *src);
#ifndef NANO_SMALL
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x);
void unpartition_filestruct(partition *p);
#endif
void renumber_all(void);
void renumber(filestruct *fileptr);
void print1opt(const char *shortflag, const char *longflag, const char
@ -496,6 +502,9 @@ char *mallocstrcpy(char *dest, const char *src);
char *mallocstrassn(char *dest, char *src);
void new_magicline(void);
#ifndef NANO_SMALL
void remove_magicline(void);
void get_totals(const filestruct *begin, const filestruct *end, int
*lines, long *size);
void mark_order(const filestruct **top, size_t *top_x, const filestruct
**bot, size_t *bot_x);
#endif

View File

@ -669,8 +669,22 @@ ssize_t do_replace_loop(const char *needle, const filestruct
#endif
#ifndef NANO_SMALL
bool old_mark_set = ISSET(MARK_ISSET);
filestruct *edittop_save = edittop, *top, *bot;
size_t top_x, bot_x;
bool right_side_up = FALSE;
/* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
* FALSE if (current, current_x) is. */
if (old_mark_set) {
/* If the mark is on, partition the filestruct so that it
* contains only the marked text, set right_side_up properly,
* set edittop to the top of the marked text, turn the mark off,
* and refresh the screen. */
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x);
right_side_up = (bot == current && bot_x == current_x);
filepart = partition_filestruct(top, top_x, bot, bot_x);
edittop = fileage;
UNSET(MARK_ISSET);
edit_refresh();
}
@ -764,18 +778,33 @@ ssize_t do_replace_loop(const char *needle, const filestruct
length_change = strlen(copy) - strlen(current->data);
#ifndef NANO_SMALL
/* Keep mark_beginx in sync with the text changes. */
if (current == mark_beginbuf && mark_beginx > current_x) {
/* If the mark was on and (mark_beginbuf, mark_begin_x)
* was the top of it, don't change mark_beginx. */
if (!old_mark_set || !right_side_up) {
if (mark_beginx < current_x + match_len)
mark_beginx = current_x;
else
mark_beginx += length_change;
}
}
#endif
if (current == real_current && current_x <= *real_current_x) {
/* Keep real_current_x in sync with the text changes. */
if (current == real_current && current_x <=
*real_current_x) {
#ifndef NANO_SMALL
/* If the mark was on and (current, current_x) was the
* top of it, don't change real_current_x. */
if (!old_mark_set || right_side_up) {
#endif
if (*real_current_x < current_x + match_len)
*real_current_x = current_x + match_len;
*real_current_x += length_change;
#ifndef NANO_SMALL
}
#endif
}
/* Set the cursor at the last character of the replacement
@ -806,15 +835,22 @@ ssize_t do_replace_loop(const char *needle, const filestruct
}
}
#ifndef NANO_SMALL
/* If the mark was on, unpartition the filestruct so that it
* contains all the text again, set edittop back to what it was
* before, turn the mark back on, and refresh the screen. */
if (old_mark_set) {
unpartition_filestruct(filepart);
edittop = edittop_save;
SET(MARK_ISSET);
edit_refresh();
}
#endif
/* If text has been added to the magicline, make a new magicline. */
if (filebot->data[0] != '\0')
new_magicline();
#ifndef NANO_SMALL
if (old_mark_set)
SET(MARK_ISSET);
#endif
return numreplaced;
}

View File

@ -441,6 +441,57 @@ void new_magicline(void)
}
#ifndef NANO_SMALL
/* Remove the magicline from filebot, if there is one. */
void remove_magicline(void)
{
if (filebot->data[0] == '\0') {
filebot = filebot->prev;
free_filestruct(filebot->next);
filebot->next = NULL;
totlines--;
totsize--;
}
}
/* Calculate the number of lines and the number of characters between
* begin and end, and return them in lines and size, respectively. */
void get_totals(const filestruct *begin, const filestruct *end, int
*lines, long *size)
{
const filestruct *f;
if (lines != NULL)
*lines = 0;
if (size != NULL)
*size = 0;
/* Go through the lines from begin to end->prev, if we can. */
for (f = begin; f != NULL && f != end; f = f->next) {
/* Count this line. */
(*lines)++;
/* Count the number of characters on this line. */
*size += strlen(f->data);
/* Count the newline if we have one. */
if (f->next != NULL)
(*size)++;
}
/* Go through the line at end, if we can. */
if (f != NULL) {
/* Count this line. */
(*lines)++;
/* Count the number of characters on this line. */
*size += strlen(f->data);
/* Count the newline if we have one. */
if (f->next != NULL)
(*size)++;
}
}
/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
* respectively, based on the locations of top and bot. */
void mark_order(const filestruct **top, size_t *top_x, const filestruct