aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/syntax.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/syntax.c')
-rw-r--r--src/nvim/syntax.c230
1 files changed, 153 insertions, 77 deletions
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 24422c71fb..1f9dbd8228 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -41,6 +41,8 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
+static bool did_syntax_onoff = false;
+
// Structure that stores information about a highlight group.
// The ID of a highlight group is also called group ID. It is the index in
// the highlight_ga array PLUS ONE.
@@ -60,8 +62,10 @@ struct hl_group {
int sg_gui; // "gui=" highlighting attributes
RgbValue sg_rgb_fg; // RGB foreground color
RgbValue sg_rgb_bg; // RGB background color
+ RgbValue sg_rgb_sp; // RGB special color
uint8_t *sg_rgb_fg_name; // RGB foreground color name
uint8_t *sg_rgb_bg_name; // RGB background color name
+ uint8_t *sg_rgb_sp_name; // RGB special color name
};
#define SG_CTERM 2 // cterm has been set
@@ -2613,33 +2617,37 @@ find_endpos (
IF_SYN_TIME(&spp_skip->sp_time));
spp_skip->sp_prog = regmatch.regprog;
if (r && regmatch.startpos[0].col <= best_regmatch.startpos[0].col) {
- /* Add offset to skip pattern match */
+ // Add offset to skip pattern match
syn_add_end_off(&pos, &regmatch, spp_skip, SPO_ME_OFF, 1);
- /* If the skip pattern goes on to the next line, there is no
- * match with an end pattern in this line. */
- if (pos.lnum > startpos->lnum)
+ // If the skip pattern goes on to the next line, there is no
+ // match with an end pattern in this line.
+ if (pos.lnum > startpos->lnum) {
break;
+ }
- line = ml_get_buf(syn_buf, startpos->lnum, FALSE);
+ line = ml_get_buf(syn_buf, startpos->lnum, false);
+ int line_len = (int)STRLEN(line);
- /* take care of an empty match or negative offset */
- if (pos.col <= matchcol)
- ++matchcol;
- else if (pos.col <= regmatch.endpos[0].col)
+ // take care of an empty match or negative offset
+ if (pos.col <= matchcol) {
+ matchcol++;
+ } else if (pos.col <= regmatch.endpos[0].col) {
matchcol = pos.col;
- else
- /* Be careful not to jump over the NUL at the end-of-line */
+ } else {
+ // Be careful not to jump over the NUL at the end-of-line
for (matchcol = regmatch.endpos[0].col;
- line[matchcol] != NUL && matchcol < pos.col;
- ++matchcol)
- ;
+ matchcol < line_len && matchcol < pos.col;
+ matchcol++) {
+ }
+ }
- /* if the skip pattern includes end-of-line, break here */
- if (line[matchcol] == NUL)
+ // if the skip pattern includes end-of-line, break here
+ if (matchcol >= line_len) {
break;
+ }
- continue; /* start with first end pattern again */
+ continue; // start with first end pattern again
}
}
@@ -3004,14 +3012,19 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
return;
next = skiptowhite(arg);
- if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8)
+ if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8) {
curwin->w_s->b_syn_spell = SYNSPL_TOP;
- else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10)
+ } else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10) {
curwin->w_s->b_syn_spell = SYNSPL_NOTOP;
- else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7)
+ } else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) {
curwin->w_s->b_syn_spell = SYNSPL_DEFAULT;
- else
+ } else {
EMSG2(_("E390: Illegal argument: %s"), arg);
+ return;
+ }
+
+ // assume spell checking changed, force a redraw
+ redraw_win_later(curwin, NOT_VALID);
}
/*
@@ -3281,17 +3294,28 @@ static void syn_cmd_off(exarg_T *eap, int syncing)
}
static void syn_cmd_onoff(exarg_T *eap, char *name)
+ FUNC_ATTR_NONNULL_ALL
{
- char buf[100];
-
+ did_syntax_onoff = true;
eap->nextcmd = check_nextcmd(eap->arg);
if (!eap->skip) {
- strcpy(buf, "so ");
+ char buf[100];
+ strncpy(buf, "so ", 4);
vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
do_cmdline_cmd(buf);
}
}
+void syn_maybe_on(void)
+{
+ if (!did_syntax_onoff) {
+ exarg_T ea;
+ ea.arg = (char_u *)"";
+ ea.skip = false;
+ syn_cmd_onoff(&ea, "syntax");
+ }
+}
+
/*
* Handle ":syntax [list]" command: list current syntax words.
*/
@@ -4183,12 +4207,16 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
break;
if (p[1] == NUL) {
EMSG2(_("E789: Missing ']': %s"), kw);
- kw = p + 2; /* skip over the NUL */
- break;
+ goto error;
}
if (p[1] == ']') {
- kw = p + 1; /* skip over the "]" */
- break;
+ if (p[2] != NUL) {
+ EMSG3(_("E890: trailing char after ']': %s]%s"),
+ kw, &p[2]);
+ goto error;
+ }
+ kw = p + 1;
+ break; // skip over the "]"
}
if (has_mbyte) {
int l = (*mb_ptr2len)(p + 1);
@@ -4203,6 +4231,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
}
}
+error:
xfree(keyword_copy);
xfree(syn_opt_arg.cont_in_list);
xfree(syn_opt_arg.next_list);
@@ -4455,12 +4484,10 @@ syn_cmd_region (
if (illegal || not_enough)
rest = NULL;
- /*
- * Must have a "start" and "end" pattern.
- */
- if (rest != NULL && (pat_ptrs[ITEM_START] == NULL ||
- pat_ptrs[ITEM_END] == NULL)) {
- not_enough = TRUE;
+ // Must have a "start" and "end" pattern.
+ if (rest != NULL && (pat_ptrs[ITEM_START] == NULL
+ || pat_ptrs[ITEM_END] == NULL)) {
+ not_enough = true;
rest = NULL;
}
@@ -4843,9 +4870,10 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
int idx;
char_u *cpo_save;
- /* need at least three chars */
- if (arg == NULL || arg[1] == NUL || arg[2] == NUL)
+ // need at least three chars
+ if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) {
return NULL;
+ }
end = skip_regexp(arg + 1, *arg, TRUE, NULL);
if (*end != *arg) { /* end delimiter not found */
@@ -4982,6 +5010,10 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
curwin->w_s->b_syn_sync_maxlines = 0;
}
} else if (STRCMP(key, "LINECONT") == 0) {
+ if (*next_arg == NUL) { // missing pattern
+ illegal = true;
+ break;
+ }
if (curwin->w_s->b_syn_linecont_pat != NULL) {
EMSG(_("E403: syntax sync: line continuations pattern specified twice"));
finished = TRUE;
@@ -5395,8 +5427,10 @@ void ex_ownsyntax(exarg_T *eap)
if (curwin->w_s == &curwin->w_buffer->b_s) {
curwin->w_s = xmalloc(sizeof(synblock_T));
memset(curwin->w_s, 0, sizeof(synblock_T));
- // TODO: Keep the spell checking as it was.
- curwin->w_p_spell = FALSE; /* No spell checking */
+ hash_init(&curwin->w_s->b_keywtab);
+ hash_init(&curwin->w_s->b_keywtab_ic);
+ // TODO: Keep the spell checking as it was. NOLINT(readability/todo)
+ curwin->w_p_spell = false; // No spell checking
clear_string_option(&curwin->w_s->b_p_spc);
clear_string_option(&curwin->w_s->b_p_spf);
clear_string_option(&curwin->w_s->b_p_spl);
@@ -5507,25 +5541,29 @@ char_u *get_syntax_name(expand_T *xp, int idx)
}
-/*
- * Function called for expression evaluation: get syntax ID at file position.
- */
-int
-syn_get_id (
+// Function called for expression evaluation: get syntax ID at file position.
+int syn_get_id(
win_T *wp,
long lnum,
colnr_T col,
- int trans, /* remove transparency */
- bool *spellp, /* return: can do spell checking */
- int keep_state /* keep state of char at "col" */
+ int trans, // remove transparency
+ bool *spellp, // return: can do spell checking
+ int keep_state // keep state of char at "col"
)
{
- /* When the position is not after the current position and in the same
- * line of the same buffer, need to restart parsing. */
+ // When the position is not after the current position and in the same
+ // line of the same buffer, need to restart parsing.
if (wp->w_buffer != syn_buf
|| lnum != current_lnum
- || col < current_col)
+ || col < current_col) {
syntax_start(wp, lnum);
+ } else if (wp->w_buffer == syn_buf
+ && lnum == current_lnum
+ && col > current_col) {
+ // next_match may not be correct when moving around, e.g. with the
+ // "skip" expression in searchpair()
+ next_match_idx = -1;
+ }
(void)get_syntax_attr(col, spellp, keep_state);
@@ -6133,12 +6171,11 @@ do_highlight (
break;
}
- /*
- * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
- * "guibg").
- */
- while (*linep && !ascii_iswhite(*linep) && *linep != '=')
- ++linep;
+ // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg",
+ // "guibg" or "guisp").
+ while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
+ linep++;
+ }
xfree(key);
key = vim_strnsave_up(key_start, (int)(linep - key_start));
linep = skipwhite(linep);
@@ -6334,18 +6371,14 @@ do_highlight (
} else
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
}
- color &= 7; /* truncate to 8 colors */
- } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) {
- switch (t_colors) {
- case 16:
- color = color_numbers_8[i];
- break;
- case 88:
- color = color_numbers_88[i];
- break;
- case 256:
- color = color_numbers_256[i];
- break;
+ color &= 7; // truncate to 8 colors
+ } else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) {
+ if (t_colors == 88) {
+ color = color_numbers_88[i];
+ } else if (t_colors >= 256) {
+ color = color_numbers_256[i];
+ } else {
+ color = color_numbers_8[i];
}
}
}
@@ -6365,7 +6398,7 @@ do_highlight (
HL_TABLE()[idx].sg_cterm_bg = color + 1;
if (is_normal_group) {
cterm_normal_bg_color = color + 1;
- {
+ if (!ui_rgb_attached()) {
must_redraw = CLEAR;
if (color >= 0) {
if (t_colors < 16)
@@ -6420,7 +6453,23 @@ do_highlight (
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
} else if (STRCMP(key, "GUISP") == 0) {
- // Ignored for now
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ if (STRCMP(arg, "NONE") != 0) {
+ HL_TABLE()[idx].sg_rgb_sp_name = (uint8_t *)xstrdup((char *)arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
+ } else {
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_sp = HL_TABLE()[idx].sg_rgb_sp;
+ }
} else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) {
// Ignored for now
} else {
@@ -6484,6 +6533,7 @@ void restore_cterm_colors(void)
{
normal_fg = -1;
normal_bg = -1;
+ normal_sp = -1;
cterm_normal_fg_color = 0;
cterm_normal_fg_bold = 0;
cterm_normal_bg_color = 0;
@@ -6500,6 +6550,7 @@ static int hl_has_settings(int idx, int check_link)
|| HL_TABLE()[idx].sg_cterm_bg != 0
|| HL_TABLE()[idx].sg_rgb_fg_name != NULL
|| HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
|| (check_link && (HL_TABLE()[idx].sg_set & SG_LINK));
}
@@ -6516,14 +6567,18 @@ static void highlight_clear(int idx)
HL_TABLE()[idx].sg_gui = 0;
HL_TABLE()[idx].sg_rgb_fg = -1;
HL_TABLE()[idx].sg_rgb_bg = -1;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
xfree(HL_TABLE()[idx].sg_rgb_fg_name);
HL_TABLE()[idx].sg_rgb_fg_name = NULL;
xfree(HL_TABLE()[idx].sg_rgb_bg_name);
HL_TABLE()[idx].sg_rgb_bg_name = NULL;
- /* Clear the script ID only when there is no link, since that is not
- * cleared. */
- if (HL_TABLE()[idx].sg_link == 0)
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ // Clear the script ID only when there is no link, since that is not
+ // cleared.
+ if (HL_TABLE()[idx].sg_link == 0) {
HL_TABLE()[idx].sg_scriptID = 0;
+ }
}
@@ -6565,7 +6620,8 @@ int get_attr_entry(attrentry_T *aep)
&& aep->cterm_bg_color == taep->cterm_bg_color
&& aep->rgb_ae_attr == taep->rgb_ae_attr
&& aep->rgb_fg_color == taep->rgb_fg_color
- && aep->rgb_bg_color == taep->rgb_bg_color) {
+ && aep->rgb_bg_color == taep->rgb_bg_color
+ && aep->rgb_sp_color == taep->rgb_sp_color) {
return i + ATTR_OFF;
}
}
@@ -6603,6 +6659,7 @@ int get_attr_entry(attrentry_T *aep)
taep->rgb_ae_attr = aep->rgb_ae_attr;
taep->rgb_fg_color = aep->rgb_fg_color;
taep->rgb_bg_color = aep->rgb_bg_color;
+ taep->rgb_sp_color = aep->rgb_sp_color;
return table->ga_len - 1 + ATTR_OFF;
}
@@ -6664,6 +6721,10 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (spell_aep->rgb_bg_color >= 0) {
new_en.rgb_bg_color = spell_aep->rgb_bg_color;
}
+
+ if (spell_aep->rgb_sp_color >= 0) {
+ new_en.rgb_sp_color = spell_aep->rgb_sp_color;
+ }
}
return get_attr_entry(&new_en);
}
@@ -6701,7 +6762,7 @@ static void highlight_list_one(int id)
didh = highlight_list_arg(id, didh, LIST_STRING,
0, sgp->sg_rgb_bg_name, "guibg");
didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, NULL, "guisp");
+ 0, sgp->sg_rgb_sp_name, "guisp");
if (sgp->sg_link && !got_int) {
(void)syn_list_header(didh, 9999, id);
@@ -6815,8 +6876,9 @@ highlight_color (
if (modec == 'g') {
if (fg)
return HL_TABLE()[id - 1].sg_rgb_fg_name;
- if (sp)
- return NULL;
+ if (sp) {
+ return HL_TABLE()[id - 1].sg_rgb_sp_name;
+ }
return HL_TABLE()[id - 1].sg_rgb_bg_name;
}
if (font || sp)
@@ -6903,7 +6965,17 @@ set_hl_attr (
// before setting attr_entry->{f,g}g_color to a other than -1
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
- sgp->sg_attr = get_attr_entry(&at_en);
+ at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
+
+ if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0
+ || at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1
+ || at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0
+ || at_en.rgb_ae_attr != 0) {
+ sgp->sg_attr = get_attr_entry(&at_en);
+ } else {
+ // If all the fields are cleared, clear the attr field back to default value
+ sgp->sg_attr = 0;
+ }
}
/*
@@ -7234,6 +7306,10 @@ int highlight_changed(void)
hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
}
+ if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) {
+ hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp;
+ }
+
highlight_ga.ga_len = hlcnt + i + 1;
set_hl_attr(hlcnt + i); /* At long last we can apply */
highlight_stlnc[i] = syn_id2attr(hlcnt + i + 1);