diff options
Diffstat (limited to 'src/color.c')
-rw-r--r-- | src/color.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..9d7ecff --- /dev/null +++ b/src/color.c @@ -0,0 +1,360 @@ +/* $Id: color.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/************************************************************************** + * color.c * + * * + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 * + * Free Software Foundation, Inc. * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3, or (at your option) * + * any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * + * 02110-1301, USA. * + * * + **************************************************************************/ + +#include "proto.h" + +#include <stdio.h> +#include <string.h> + +#ifdef ENABLE_COLOR + +/* For each syntax list entry, go through the list of colors and assign + * the color pairs. */ +void set_colorpairs(void) +{ + const syntaxtype *this_syntax = syntaxes; + + for (; this_syntax != NULL; this_syntax = this_syntax->next) { + colortype *this_color = this_syntax->color; + int color_pair = 1; + + for (; this_color != NULL; this_color = this_color->next) { + const colortype *beforenow = this_syntax->color; + + for (; beforenow != this_color && + (beforenow->fg != this_color->fg || + beforenow->bg != this_color->bg || + beforenow->bright != this_color->bright); + beforenow = beforenow->next) + ; + + if (beforenow != this_color) + this_color->pairnum = beforenow->pairnum; + else { + this_color->pairnum = color_pair; + color_pair++; + } + } + } +} + +/* Initialize the color information. */ +void color_init(void) +{ + assert(openfile != NULL); + + if (has_colors()) { + const colortype *tmpcolor; +#ifdef HAVE_USE_DEFAULT_COLORS + bool defok; +#endif + + start_color(); + +#ifdef HAVE_USE_DEFAULT_COLORS + /* Use the default colors, if available. */ + defok = (use_default_colors() != ERR); +#endif + + for (tmpcolor = openfile->colorstrings; tmpcolor != NULL; + tmpcolor = tmpcolor->next) { + short foreground = tmpcolor->fg, background = tmpcolor->bg; + if (foreground == -1) { +#ifdef HAVE_USE_DEFAULT_COLORS + if (!defok) +#endif + foreground = COLOR_WHITE; + } + + if (background == -1) { +#ifdef HAVE_USE_DEFAULT_COLORS + if (!defok) +#endif + background = COLOR_BLACK; + } + + init_pair(tmpcolor->pairnum, foreground, background); + +#ifdef DEBUG + fprintf(stderr, "init_pair(): fg = %hd, bg = %hd\n", tmpcolor->fg, tmpcolor->bg); +#endif + } + } +} + +/* Update the color information based on the current filename. */ +void color_update(void) +{ + syntaxtype *tmpsyntax; + syntaxtype *defsyntax = NULL; + colortype *tmpcolor, *defcolor = NULL; + + assert(openfile != NULL); + + openfile->syntax = NULL; + openfile->colorstrings = NULL; + + /* If we specified a syntax override string, use it. */ + if (syntaxstr != NULL) { + /* If the syntax override is "none", it's the same as not having + * a syntax at all, so get out. */ + if (strcmp(syntaxstr, "none") == 0) + return; + + for (tmpsyntax = syntaxes; tmpsyntax != NULL; + tmpsyntax = tmpsyntax->next) { + if (strcmp(tmpsyntax->desc, syntaxstr) == 0) { + openfile->syntax = tmpsyntax; + openfile->colorstrings = tmpsyntax->color; + } + + if (openfile->colorstrings != NULL) + break; + } + } + + /* If we didn't specify a syntax override string, or if we did and + * there was no syntax by that name, get the syntax based on the + * file extension, and then look in the header. */ + if (openfile->colorstrings == NULL) { + for (tmpsyntax = syntaxes; tmpsyntax != NULL; + tmpsyntax = tmpsyntax->next) { + exttype *e; + + /* If this is the default syntax, it has no associated + * extensions, which we've checked for elsewhere. Skip over + * it here, but keep track of its color regexes. */ + if (strcmp(tmpsyntax->desc, "default") == 0) { + defsyntax = tmpsyntax; + defcolor = tmpsyntax->color; + continue; + } + + for (e = tmpsyntax->extensions; e != NULL; e = e->next) { + bool not_compiled = (e->ext == NULL); + + /* e->ext_regex has already been checked for validity + * elsewhere. Compile its specified regex if we haven't + * already. */ + if (not_compiled) { + e->ext = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED); + } + + /* Set colorstrings if we matched the extension + * regex. */ + if (regexec(e->ext, openfile->filename, 0, NULL, + 0) == 0) { + openfile->syntax = tmpsyntax; + openfile->colorstrings = tmpsyntax->color; + } + + if (openfile->colorstrings != NULL) + break; + + /* Decompile e->ext_regex's specified regex if we aren't + * going to use it. */ + if (not_compiled) { + regfree(e->ext); + free(e->ext); + e->ext = NULL; + } + } + } + + /* If we haven't matched anything yet, try the headers */ + if (openfile->colorstrings == NULL) { +#ifdef DEBUG + fprintf(stderr, "No match for file extensions, looking at headers...\n"); +#endif + for (tmpsyntax = syntaxes; tmpsyntax != NULL; + tmpsyntax = tmpsyntax->next) { + exttype *e; + + for (e = tmpsyntax->headers; e != NULL; e = e->next) { + bool not_compiled = (e->ext == NULL); + + /* e->ext_regex has already been checked for validity + * elsewhere. Compile its specified regex if we haven't + * already. */ + if (not_compiled) { + e->ext = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED); + } + + /* Set colorstrings if we matched the extension + * regex. */ +#ifdef DEBUG + fprintf(stderr, "Comparing header regex \"%s\" to fileage \"%s\"...\n", e->ext_regex, openfile->fileage->data); +#endif + if (regexec(e->ext, openfile->fileage->data, 0, NULL, 0) == 0) { + openfile->syntax = tmpsyntax; + openfile->colorstrings = tmpsyntax->color; + } + + if (openfile->colorstrings != NULL) + break; + + /* Decompile e->ext_regex's specified regex if we aren't + * going to use it. */ + if (not_compiled) { + regfree(e->ext); + free(e->ext); + e->ext = NULL; + } + } + } + } + } + + + /* If we didn't get a syntax based on the file extension, and we + * have a default syntax, use it. */ + if (openfile->colorstrings == NULL && defcolor != NULL) { + openfile->syntax = defsyntax; + openfile->colorstrings = defcolor; + } + + for (tmpcolor = openfile->colorstrings; tmpcolor != NULL; + tmpcolor = tmpcolor->next) { + /* tmpcolor->start_regex and tmpcolor->end_regex have already + * been checked for validity elsewhere. Compile their specified + * regexes if we haven't already. */ + if (tmpcolor->start == NULL) { + tmpcolor->start = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(tmpcolor->start, fixbounds(tmpcolor->start_regex), + REG_EXTENDED | (tmpcolor->icase ? REG_ICASE : 0)); + } + + if (tmpcolor->end_regex != NULL && tmpcolor->end == NULL) { + tmpcolor->end = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(tmpcolor->end, fixbounds(tmpcolor->end_regex), + REG_EXTENDED | (tmpcolor->icase ? REG_ICASE : 0)); + } + } +} + +/* Reset the multicolor info cache for records for any lines which need + to be recalculated */ +void reset_multis_after(filestruct *fileptr, int mindex) +{ + filestruct *oof; + for (oof = fileptr->next; oof != NULL; oof = oof->next) { + alloc_multidata_if_needed(oof); + if (oof->multidata == NULL) + continue; + if (oof->multidata[mindex] != CNONE) + oof->multidata[mindex] = -1; + else + break; + } + for (; oof != NULL; oof = oof->next) { + alloc_multidata_if_needed(oof); + if (oof->multidata == NULL) + continue; + if (oof->multidata[mindex] == CNONE) + oof->multidata[mindex] = -1; + else + break; + } + edit_refresh_needed = TRUE; +} + +void reset_multis_before(filestruct *fileptr, int mindex) +{ + filestruct *oof; + for (oof = fileptr->prev; oof != NULL; oof = oof->prev) { + alloc_multidata_if_needed(oof); + if (oof->multidata == NULL) + continue; + if (oof->multidata[mindex] != CNONE) + oof->multidata[mindex] = -1; + else + break; + } + for (; oof != NULL; oof = oof->prev) { + alloc_multidata_if_needed(oof); + if (oof->multidata == NULL) + continue; + if (oof->multidata[mindex] == CNONE) + oof->multidata[mindex] = -1; + else + break; + } + + edit_refresh_needed = TRUE; +} + +/* Reset one multiline regex info */ +void reset_multis_for_id(filestruct *fileptr, int num) +{ + reset_multis_before(fileptr, num); + reset_multis_after(fileptr, num); + fileptr->multidata[num] = -1; +} + +/* Reset multi line strings around a filestruct ptr, trying to be smart about stopping + force = reset everything regardless, useful when we don't know how much screen state + has changed */ +void reset_multis(filestruct *fileptr, bool force) +{ + int nobegin, noend; + regmatch_t startmatch, endmatch; + const colortype *tmpcolor = openfile->colorstrings; + + if (!openfile->syntax) + return; + + for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) { + + /* If it's not a multi-line regex, amscray */ + if (tmpcolor->end == NULL) + continue; + + alloc_multidata_if_needed(fileptr); + if (force == TRUE) { + reset_multis_for_id(fileptr, tmpcolor->id); + continue; + } + + /* Figure out where the first begin and end are to determine if + things changed drastically for the precalculated multi values */ + nobegin = regexec(tmpcolor->start, fileptr->data, 1, &startmatch, 0); + noend = regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0); + if (fileptr->multidata[tmpcolor->id] == CWHOLELINE) { + if (nobegin && noend) + continue; + } else if (fileptr->multidata[tmpcolor->id] == CNONE) { + if (nobegin && noend) + continue; + } else if (fileptr->multidata[tmpcolor->id] & CBEGINBEFORE && !noend + && (nobegin || endmatch.rm_eo > startmatch.rm_eo)) { + reset_multis_after(fileptr, tmpcolor->id); + continue; + } + + /* If we got here assume the worst */ + reset_multis_for_id(fileptr, tmpcolor->id); + } +} +#endif /* ENABLE_COLOR */ |