Skip to content

Commit

Permalink
patch 9.1.0030: Cannot use terminal alternate font
Browse files Browse the repository at this point in the history
Problem:  Cannot use terminal alternate fonts (PMunch)
Solution: Support terminal alternate fonts using
          CSI SGR 10-20 and t_CF code (PMunch)

Add support for alternate font highlighting

This adds support for alternate font highlighting using CSI SGR 10-20.
Few terminals currently support this, but with added tool support this
should improve over time. The change here is more or less taken from how
colors are configured and applied, but there might be some parts I
missed while implementing it. Changing fonts is done through the new
`:hi ctermfont` attribute which takes a number, 0 is the normal font, and
the numbers 1-9 select an "alternative" font. Which fonts are in use is
up to the terminal.

fixes: #13513
closes: #13537

Signed-off-by: PMunch <peterme@peterme.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
  • Loading branch information
PMunch authored and chrisbra committed Jan 15, 2024
1 parent eb3475d commit a606f3a
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 8 deletions.
8 changes: 8 additions & 0 deletions runtime/doc/syntax.txt
Expand Up @@ -5304,6 +5304,14 @@ ctermul={color-nr} *highlight-ctermul*
command is given. If the Normal group colors are changed later, the
"fg" and "bg" colors will not be adjusted.

ctermfont={font-nr} *highlight-ctermfont*
This gives the alternative font number to use in the terminal. The
available fonts depend on the terminal, and if the terminal is not set
up for alternative fonts this simply won't do anything. The range of
{font-nr} is 0-10 where 0 resets the font to the default font, 1-9
selects one of the 9 alternate fonts, and 10 selects the Fraktur font.
For more information see your terminal's handling of SGR parameters
10-20. |t_CF|

3. highlight arguments for the GUI

Expand Down
1 change: 1 addition & 0 deletions runtime/doc/tags
Expand Up @@ -7947,6 +7947,7 @@ highlight-clear syntax.txt /*highlight-clear*
highlight-cterm syntax.txt /*highlight-cterm*
highlight-ctermbg syntax.txt /*highlight-ctermbg*
highlight-ctermfg syntax.txt /*highlight-ctermfg*
highlight-ctermfont syntax.txt /*highlight-ctermfont*
highlight-ctermul syntax.txt /*highlight-ctermul*
highlight-default syntax.txt /*highlight-default*
highlight-font syntax.txt /*highlight-font*
Expand Down
3 changes: 2 additions & 1 deletion runtime/doc/term.txt
@@ -1,4 +1,4 @@
*term.txt* For Vim version 9.1. Last change: 2023 Dec 09
*term.txt* For Vim version 9.1. Last change: 2024 Jan 15


VIM REFERENCE MANUAL by Bram Moolenaar
Expand Down Expand Up @@ -448,6 +448,7 @@ Added by Vim (there are no standard codes for these):
t_AU set underline color (ANSI) *t_AU* *'t_AU'*
t_Ce undercurl and underline end *t_Ce* *'t_Ce'*
t_Cs undercurl (curly underline) mode *t_Cs* *'t_Cs'*
t_CF set alternate font (using index 0 - 10) *t_CF* *'t_CF'*
t_Us double underline mode *t_Us* *'t_Us'*
t_ds dotted underline mode *t_ds* *'t_ds'*
t_Ds dashed underline mode *t_Ds* *'t_Ds'*
Expand Down
5 changes: 4 additions & 1 deletion runtime/syntax/vim.vim
Expand Up @@ -9,6 +9,7 @@
" 2023 Dec 21 by Vim Project (improve ex command matching)
" 2023 Dec 30 by Vim Project (:syntax improvements)
" 2024 Jan 14 by Vim Project (TermResponseAll autocommand)
" 2024 Jan 15 by Vim Project (:hi ctermfont attribute)
" Version: 9.0-25
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM
" Automatically generated keyword lists: {{{1
Expand Down Expand Up @@ -663,7 +664,7 @@ syn match vimHiGuiFontname contained "'[a-zA-Z\-* ]\+'"
syn match vimHiGuiRgb contained "#\x\{6}"

" Highlighting: hi group key=arg ... {{{2
syn cluster vimHiCluster contains=vimGroup,vimHiGroup,vimHiTerm,vimHiCTerm,vimHiStartStop,vimHiCtermFgBg,vimHiCtermul,vimHiGui,vimHiGuiFont,vimHiGuiFgBg,vimHiKeyError,vimNotation
syn cluster vimHiCluster contains=vimGroup,vimHiGroup,vimHiTerm,vimHiCTerm,vimHiStartStop,vimHiCtermFgBg,vimHiCtermul,vimHiCtermfont,vimHiGui,vimHiGuiFont,vimHiGuiFgBg,vimHiKeyError,vimNotation
syn region vimHiKeyList contained oneline start="\i\+" skip="\\\\\|\\|" end="$\||" contains=@vimHiCluster
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_vimhikeyerror")
syn match vimHiKeyError contained "\i\+="he=e-1
Expand All @@ -673,6 +674,7 @@ syn match vimHiStartStop contained "\c\(start\|stop\)="he=e-1 nextgroup=vimHiTer
syn match vimHiCTerm contained "\ccterm="he=e-1 nextgroup=vimHiAttribList
syn match vimHiCtermFgBg contained "\ccterm[fb]g="he=e-1 nextgroup=vimHiNmbr,vimHiCtermColor,vimFgBgAttrib,vimHiCtermError
syn match vimHiCtermul contained "\cctermul="he=e-1 nextgroup=vimHiNmbr,vimHiCtermColor,vimFgBgAttrib,vimHiCtermError
syn match vimHiCtermfont contained "\cctermfont="he=e-1 nextgroup=vimHiNmbr,vimHiCtermColor,vimFgBgAttrib,vimHiCtermError
syn match vimHiGui contained "\cgui="he=e-1 nextgroup=vimHiAttribList
syn match vimHiGuiFont contained "\cfont="he=e-1 nextgroup=vimHiFontname
syn match vimHiGuiFgBg contained "\cgui\%([fb]g\|sp\)="he=e-1 nextgroup=vimHiGroup,vimHiGuiFontname,vimHiGuiRgb,vimFgBgAttrib
Expand Down Expand Up @@ -951,6 +953,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vimFgBgAttrib vimHiAttrib
hi def link vimFuncEcho vimCommand
hi def link vimHiCtermul vimHiTerm
hi def link vimHiCtermfont vimHiTerm
hi def link vimFold Folded
hi def link vimFor vimCommand
hi def link vimFTCmd vimCommand
Expand Down
74 changes: 71 additions & 3 deletions src/highlight.c
Expand Up @@ -59,6 +59,7 @@ typedef struct
int sg_cterm_bg; // terminal bg color number + 1
int sg_cterm_ul; // terminal ul color number + 1
int sg_cterm_attr; // Screen attr for color term mode
int sg_cterm_font; // terminal alternative font (0 for normal)
// for when using the GUI
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
guicolor_T sg_gui_fg; // GUI foreground color handle
Expand Down Expand Up @@ -1034,6 +1035,39 @@ highlight_set_ctermul(int idx, int color, int is_normal_group)
hl_set_ctermul_normal_group(color);
}

/*
* Set the cterm font for the highlight group at 'idx'.
* 'arg' is the color name or the numeric value as a string.
* 'init' is set to TRUE when initializing highlighting.
* Called for the ":highlight" command and the "hlset()" function.
*
* Returns TRUE if the font is set.
*/
static int
highlight_set_cterm_font(
int idx,
char_u *arg,
int init)
{
int font;

if (init && (HL_TABLE()[idx].sg_set & SG_CTERM))
return FALSE;

if (!init)
HL_TABLE()[idx].sg_set |= SG_CTERM;

if (VIM_ISDIGIT(*arg))
font = atoi((char *)arg);
else if (STRICMP(arg, "NONE") == 0)
font = -1;
else
return FALSE;

HL_TABLE()[idx].sg_cterm_font = font + 1;
return TRUE;
}

/*
* Set the cterm fg/bg/ul color for the highlight group at 'idx'.
* 'key' is one of 'CTERMFG' or 'CTERMBG' or 'CTERMUL'.
Expand Down Expand Up @@ -1679,6 +1713,14 @@ do_highlight(
break;
}
}
else if (STRCMP(key, "CTERMFONT") == 0)
{
if (!highlight_set_cterm_font(idx, arg, init))
{
error = TRUE;
break;
}
}
else if (STRCMP(key, "GUIFG") == 0)
{
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
Expand Down Expand Up @@ -1865,6 +1907,7 @@ hl_has_settings(int idx, int check_link)
|| HL_TABLE()[idx].sg_cterm_attr != 0
|| HL_TABLE()[idx].sg_cterm_fg != 0
|| HL_TABLE()[idx].sg_cterm_bg != 0
|| HL_TABLE()[idx].sg_cterm_font != 0
#ifdef FEAT_GUI
|| HL_TABLE()[idx].sg_gui_attr != 0
|| HL_TABLE()[idx].sg_gui_fg_name != NULL
Expand Down Expand Up @@ -1892,6 +1935,7 @@ highlight_clear(int idx)
HL_TABLE()[idx].sg_cterm_fg = 0;
HL_TABLE()[idx].sg_cterm_bg = 0;
HL_TABLE()[idx].sg_cterm_attr = 0;
HL_TABLE()[idx].sg_cterm_font = 0;
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
HL_TABLE()[idx].sg_gui = 0;
VIM_CLEAR(HL_TABLE()[idx].sg_gui_fg_name);
Expand Down Expand Up @@ -2539,6 +2583,8 @@ get_attr_entry(garray_T *table, attrentry_T *aep)
== taep->ae_u.cterm.bg_color
&& aep->ae_u.cterm.ul_color
== taep->ae_u.cterm.ul_color
&& aep->ae_u.cterm.font
== taep->ae_u.cterm.font
#ifdef FEAT_TERMGUICOLORS
&& aep->ae_u.cterm.fg_rgb
== taep->ae_u.cterm.fg_rgb
Expand Down Expand Up @@ -2609,6 +2655,7 @@ get_attr_entry(garray_T *table, attrentry_T *aep)
taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
taep->ae_u.cterm.ul_color = aep->ae_u.cterm.ul_color;
taep->ae_u.cterm.font = aep->ae_u.cterm.font;
#ifdef FEAT_TERMGUICOLORS
taep->ae_u.cterm.fg_rgb = aep->ae_u.cterm.fg_rgb;
taep->ae_u.cterm.bg_rgb = aep->ae_u.cterm.bg_rgb;
Expand Down Expand Up @@ -2639,6 +2686,7 @@ get_cterm_attr_idx(int attr, int fg, int bg)
at_en.ae_u.cterm.fg_color = fg;
at_en.ae_u.cterm.bg_color = bg;
at_en.ae_u.cterm.ul_color = 0;
at_en.ae_u.cterm.font = 0;
return get_attr_entry(&cterm_attr_table, &at_en);
}
#endif
Expand Down Expand Up @@ -2809,6 +2857,8 @@ hl_combine_attr(int char_attr, int prim_attr)
new_en.ae_u.cterm.bg_color = prim_aep->ae_u.cterm.bg_color;
if (prim_aep->ae_u.cterm.ul_color > 0)
new_en.ae_u.cterm.ul_color = prim_aep->ae_u.cterm.ul_color;
if (prim_aep->ae_u.cterm.font > 0)
new_en.ae_u.cterm.font = prim_aep->ae_u.cterm.font;
#ifdef FEAT_TERMGUICOLORS
// If both fg and bg are not set fall back to cterm colors.
// Helps for SpellBad which uses undercurl in the GUI.
Expand Down Expand Up @@ -2948,6 +2998,8 @@ highlight_list_one(int id)
sgp->sg_cterm_bg, NULL, "ctermbg");
didh = highlight_list_arg(id, didh, LIST_INT,
sgp->sg_cterm_ul, NULL, "ctermul");
didh = highlight_list_arg(id, didh, LIST_INT,
sgp->sg_cterm_font, NULL, "ctermfont");

#if defined(FEAT_GUI) || defined(FEAT_EVAL)
didh = highlight_list_arg(id, didh, LIST_ATTR,
Expand Down Expand Up @@ -3138,14 +3190,16 @@ highlight_color(
return (HL_TABLE()[id - 1].sg_gui_sp_name);
return (HL_TABLE()[id - 1].sg_gui_bg_name);
}
if (font || sp)
if (sp)
return NULL;
if (modec == 'c')
{
if (fg)
n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
else if (ul)
n = HL_TABLE()[id - 1].sg_cterm_ul - 1;
else if (font)
n = HL_TABLE()[id - 1].sg_cterm_font - 1;
else
n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
if (n < 0)
Expand Down Expand Up @@ -3296,7 +3350,8 @@ set_hl_attr(

// For the color term mode: If there are other than "normal"
// highlighting attributes, need to allocate an attr number.
if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 && sgp->sg_cterm_ul == 0
if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 &&
sgp->sg_cterm_ul == 0 && sgp->sg_cterm_font == 0
# ifdef FEAT_TERMGUICOLORS
&& sgp->sg_gui_fg == INVALCOLOR
&& sgp->sg_gui_bg == INVALCOLOR
Expand All @@ -3310,6 +3365,7 @@ set_hl_attr(
at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
at_en.ae_u.cterm.ul_color = sgp->sg_cterm_ul;
at_en.ae_u.cterm.font = sgp->sg_cterm_font;
# ifdef FEAT_TERMGUICOLORS
at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg);
at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg);
Expand Down Expand Up @@ -3717,6 +3773,8 @@ combine_stl_hlt(
hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg)
hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
if (hlt[id - 1].sg_cterm_font != hlt[id_S - 1].sg_cterm_font)
hlt[hlcnt + i].sg_cterm_font = hlt[id - 1].sg_cterm_font;
# if defined(FEAT_GUI) || defined(FEAT_EVAL)
hlt[hlcnt + i].sg_gui ^=
hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
Expand Down Expand Up @@ -4180,6 +4238,10 @@ highlight_get_info(int hl_idx, int resolve_link)
if (dict_add_string(dict, "ctermul",
highlight_color(hlgid, (char_u *)"ul", 'c')) == FAIL)
goto error;
if (sgp->sg_cterm_font != 0)
if (dict_add_string(dict, "ctermfont",
highlight_color(hlgid, (char_u *)"font", 'c')) == FAIL)
goto error;
if (sgp->sg_gui != 0)
{
attr_dict = highlight_get_attr_dict(sgp->sg_gui);
Expand Down Expand Up @@ -4408,6 +4470,7 @@ hlg_add_or_update(dict_T *dict)
char_u *ctermfg;
char_u *ctermbg;
char_u *ctermul;
char_u *ctermfont;
char_u *guifg;
char_u *guibg;
char_u *guisp;
Expand Down Expand Up @@ -4492,6 +4555,10 @@ hlg_add_or_update(dict_T *dict)
if (error)
return FALSE;

ctermfont = hldict_get_string(dict, (char_u *)"ctermfont", &error);
if (error)
return FALSE;

if (!hldict_attr_to_str(dict, (char_u *)"gui", gui_attr, sizeof(gui_attr)))
return FALSE;

Expand All @@ -4516,7 +4583,7 @@ hlg_add_or_update(dict_T *dict)
// If none of the attributes are specified, then do nothing.
if (term_attr[0] == NUL && start == NULL && stop == NULL
&& cterm_attr[0] == NUL && ctermfg == NULL && ctermbg == NULL
&& ctermul == NULL && gui_attr[0] == NUL
&& ctermul == NULL && ctermfont == NULL && gui_attr[0] == NUL
# ifdef FEAT_GUI
&& font == NULL
# endif
Expand All @@ -4536,6 +4603,7 @@ hlg_add_or_update(dict_T *dict)
p = add_attr_and_value(p, (char_u *)" ctermfg=", 9, ctermfg);
p = add_attr_and_value(p, (char_u *)" ctermbg=", 9, ctermbg);
p = add_attr_and_value(p, (char_u *)" ctermul=", 9, ctermul);
p = add_attr_and_value(p, (char_u *)" ctermfont=", 9, ctermfont);
p = add_attr_and_value(p, (char_u *)" gui=", 5, gui_attr);
# ifdef FEAT_GUI
p = add_attr_and_value(p, (char_u *)" font=", 6, font);
Expand Down
1 change: 1 addition & 0 deletions src/optiondefs.h
Expand Up @@ -2931,6 +2931,7 @@ static struct vimoption options[] =
p_term("t_cd", T_CD)
p_term("t_ce", T_CE)
p_term("t_Ce", T_UCE)
p_term("t_CF", T_CFO)
p_term("t_cl", T_CL)
p_term("t_cm", T_CM)
p_term("t_Co", T_CCO)
Expand Down
1 change: 1 addition & 0 deletions src/proto/term.pro
Expand Up @@ -33,6 +33,7 @@ void term_set_winsize(int height, int width);
void term_fg_color(int n);
void term_bg_color(int n);
void term_ul_color(int n);
void term_font(int n);
char_u *term_bg_default(void);
void term_fg_rgb_color(guicolor_T rgb);
void term_bg_rgb_color(guicolor_T rgb);
Expand Down
2 changes: 2 additions & 0 deletions src/screen.c
Expand Up @@ -1667,6 +1667,8 @@ screen_start_highlight(int attr)
*/
if (aep != NULL)
{
if (aep->ae_u.cterm.font > 0 && aep->ae_u.cterm.font < 12)
term_font(aep->ae_u.cterm.font);
#ifdef FEAT_TERMGUICOLORS
// When 'termguicolors' is set but fg or bg is unset,
// fall back to the cterm colors. This helps for SpellBad,
Expand Down
1 change: 1 addition & 0 deletions src/structs.h
Expand Up @@ -1186,6 +1186,7 @@ typedef struct attr_entry
short_u fg_color; // foreground color number
short_u bg_color; // background color number
short_u ul_color; // underline color number
short_u font; // font number
# ifdef FEAT_TERMGUICOLORS
guicolor_T fg_rgb; // foreground color RGB
guicolor_T bg_rgb; // background color RGB
Expand Down
23 changes: 22 additions & 1 deletion src/term.c
Expand Up @@ -625,7 +625,7 @@ static tcap_entry_T builtin_kitty[] = {

#ifdef FEAT_TERMGUICOLORS
/*
* Additions for using the RGB colors
* Additions for using the RGB colors and terminal font
*/
static tcap_entry_T builtin_rgb[] = {
// These are printf strings, not terminal codes.
Expand All @@ -637,6 +637,12 @@ static tcap_entry_T builtin_rgb[] = {
};
#endif

static tcap_entry_T special_term[] = {
// These are printf strings, not terminal codes.
{(int)KS_CF, "\033[%dm"},
{(int)KS_NAME, NULL} // end marker
};

/*
* iris-ansi for Silicon Graphics machines.
*/
Expand Down Expand Up @@ -1235,6 +1241,7 @@ static tcap_entry_T builtin_debug[] = {
{(int)KS_U7, "[U7]"},
{(int)KS_RFG, "[RFG]"},
{(int)KS_RBG, "[RBG]"},
{(int)KS_CF, "[CF%d]"},
{K_UP, "[KU]"},
{K_DOWN, "[KD]"},
{K_LEFT, "[KL]"},
Expand Down Expand Up @@ -1754,6 +1761,7 @@ get_term_entries(int *height, int *width)
{KS_CBE, "BE"}, {KS_CBD, "BD"},
{KS_CST, "ST"}, {KS_CRT, "RT"},
{KS_SSI, "Si"}, {KS_SRI, "Ri"},
{KS_CF, "CF"},
{(enum SpecialKey)0, NULL}
};
int i;
Expand Down Expand Up @@ -2113,6 +2121,8 @@ set_termname(char_u *term)
&& term_strings_not_set(KS_8U))
apply_builtin_tcap(term, builtin_rgb, TRUE);
#endif
if (term_strings_not_set(KS_CF))
apply_builtin_tcap(term, special_term, TRUE);
}

/*
Expand Down Expand Up @@ -3116,6 +3126,17 @@ term_set_winsize(int height, int width)
}
#endif

void
term_font(int n)
{
if (*T_CFO)
{
char buf[20];
sprintf(buf, (char *)T_CFO, 9 + n);
OUT_STR(buf);
}
}

static void
term_color(char_u *s, int n)
{
Expand Down

0 comments on commit a606f3a

Please sign in to comment.