diff --git a/docs/changelog.rst b/docs/changelog.rst index a3c571aa4..d24d625f5 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -19,6 +19,9 @@ To update |kitty|, :doc:`follow the instructions `. - Allow rendering the cursor with a *reverse video* effect. See :opt:`cursor` for details (:iss:`126`) +- Allow rendering the mouse selection with a *reverse video* effect. See + :opt:`selection_foreground` (:iss:`646`) + - A new option :opt:`tab_bar_align` to draw the tab bar centered or right aligned (:iss:`3946`) diff --git a/kitty/cell_vertex.glsl b/kitty/cell_vertex.glsl index 6c5cb3eb8..8d8f10a3b 100644 --- a/kitty/cell_vertex.glsl +++ b/kitty/cell_vertex.glsl @@ -12,7 +12,7 @@ // Inputs {{{ layout(std140) uniform CellRenderData { - float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_fg_for_selection; + float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_for_selection_fg, use_cell_for_selection_bg; uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted; @@ -170,6 +170,7 @@ void main() { uint bg_as_uint = resolve_color(colors[bg_index], default_colors[bg_index]); bg_as_uint = has_mark * color_table[NUM_COLORS + mark] + (ONE - has_mark) * bg_as_uint; vec3 bg = color_to_vec(bg_as_uint); + uint fg_as_uint = resolve_color(colors[fg_index], default_colors[fg_index]); // }}} // Foreground {{{ @@ -180,7 +181,6 @@ void main() { colored_sprite = float((sprite_coords.z & COLOR_MASK) >> 14); // Foreground - uint fg_as_uint = resolve_color(colors[fg_index], default_colors[fg_index]); fg_as_uint = has_mark * color_table[NUM_COLORS + MARK_MASK + 1 + mark] + (ONE - has_mark) * fg_as_uint; foreground = color_to_vec(fg_as_uint); float has_dim = float((text_attrs >> DIM_SHIFT) & ONE); @@ -189,7 +189,7 @@ void main() { decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], fg_as_uint)); #ifdef USE_SELECTION_FG // Selection - vec3 selection_color = choose_color(use_fg_for_selection, foreground, color_to_vec(highlight_fg)); + vec3 selection_color = choose_color(use_cell_for_selection_fg, bg, color_to_vec(highlight_fg)); foreground = choose_color(float(is_selected & ONE), selection_color, foreground); decoration_fg = choose_color(float(is_selected & ONE), selection_color, decoration_fg); #endif @@ -236,7 +236,7 @@ void main() { #if defined(SPECIAL) || defined(SIMPLE) // Selection and cursor - bg = choose_color(float(is_selected & ONE), color_to_vec(highlight_bg), bg); + bg = choose_color(float(is_selected & ONE), choose_color(use_cell_for_selection_bg, color_to_vec(fg_as_uint), color_to_vec(highlight_bg)), bg); background = choose_color(cell_has_block_cursor, color_to_vec(cursor_bg), bg); #if !defined(TRANSPARENT) && defined(SPECIAL) float is_special_cell = cell_has_block_cursor + float(is_selected & ONE); diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 42c0b214f..4a77362ca 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -1146,15 +1146,13 @@ and zero means fully dimmed (i.e. invisible). opt('selection_foreground', '#000000', option_type='to_color_or_none', long_text=''' -The foreground for text selected with the mouse. A value of none means to leave -the color unchanged. -''' - ) +The foreground and background colors for text selected with the mouse. Setting both of +these to :code:`none` will cause a "reverse video" effect for selections, where the +selection will be the cell text color and the text will become the cell background color. +Note that these colors can be overridden by the program running in the terminal. +''') -opt('selection_background', '#fffacd', - option_type='to_color', - long_text='The background for text selected with the mouse.' - ) +opt('selection_background', '#fffacd', option_type='to_color_or_none',) # colors.table {{{ diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 06b1a74a5..bd1b7f9a8 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -1125,7 +1125,7 @@ class Parser: ans['select_by_word_characters'] = str(val) def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: - ans['selection_background'] = to_color(val) + ans['selection_background'] = to_color_or_none(val) def selection_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['selection_foreground'] = to_color_or_none(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index dba237933..a0b832312 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -537,7 +537,7 @@ class Options: scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER'] scrollback_pager_history_size: int = 0 select_by_word_characters: str = '@-./_~?&=%+#' - selection_background: Color = Color(255, 250, 205) + selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205) selection_foreground: typing.Optional[kitty.fast_data_types.Color] = Color(0, 0, 0) shell: str = '.' shell_integration: str = 'enabled' diff --git a/kitty/rc/set_colors.py b/kitty/rc/set_colors.py index 2dece5ecd..6a7de869b 100644 --- a/kitty/rc/set_colors.py +++ b/kitty/rc/set_colors.py @@ -17,7 +17,10 @@ if TYPE_CHECKING: from kitty.cli_stub import SetColorsRCOptions as CLIOptions -nullable_colors = ('cursor', 'cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color', 'selection_foreground', 'active_border_color') +nullable_colors = ( + 'cursor', 'cursor_text_color', 'tab_bar_background', 'tab_bar_margin_color', + 'selection_foreground', 'selection_background', 'active_border_color' +) def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]: diff --git a/kitty/shaders.c b/kitty/shaders.c index d14e47a3f..401861e78 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -276,7 +276,7 @@ pick_cursor_color(Line *line, ColorProfile *color_profile, color_type cell_fg, c static void cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor, bool inverted, OSWindow *os_window) { struct CellRenderData { - GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_fg_for_selection; + GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_for_selection_fg, use_cell_for_selection_bg; GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted; @@ -295,7 +295,8 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg); // selection - rd->use_fg_for_selection = IS_SPECIAL_COLOR(highlight_fg) ? 1. : 0.; + rd->use_cell_for_selection_fg = IS_SPECIAL_COLOR(highlight_fg) ? 1. : 0.; + rd->use_cell_for_selection_bg = IS_SPECIAL_COLOR(highlight_bg) ? 1. : 0.; // Cursor position enum { BLOCK_IDX = 0, BEAM_IDX = 6, UNDERLINE_IDX = 7, UNFOCUSED_IDX = 8 }; if (cursor->is_visible) {