mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-24 09:18:08 +02:00
Implement a simple scroll progress indicator
Shows a simple bar on the right edge of the window that moves up as you scroll further back. There are apparently a lot of people that dont use a pager for browsing large scrollbacks. I will never understand this, but, what the hell I was in that code area anyway for other reasons. TODO: Maybe make it a rounded rectangle
This commit is contained in:
@@ -54,6 +54,8 @@ Detailed list of changes
|
|||||||
using the panel kitten for all compositors that support the requisite Wayland
|
using the panel kitten for all compositors that support the requisite Wayland
|
||||||
protocol which is practically speaking all of them but GNOME (:pull:`2590`)
|
protocol which is practically speaking all of them but GNOME (:pull:`2590`)
|
||||||
|
|
||||||
|
- A new option :opt:`scrollback_indicator_opacity` to show a small indicator on the right hand side of the screen of how much you have scrolled
|
||||||
|
|
||||||
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
|
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
|
||||||
|
|
||||||
- Wayland: Support preferred integer scales
|
- Wayland: Support preferred integer scales
|
||||||
|
|||||||
@@ -374,6 +374,14 @@ is changed it will only affect newly created windows, not existing ones.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
opt('scrollback_indicator_opacity', '0.0',
|
||||||
|
option_type='unit_float', ctype='float', long_text='''
|
||||||
|
The opacity of the scrollback indicator which is a small colored rectangle that moves
|
||||||
|
along the right hand side of the window as you scroll, indicating what fraction you
|
||||||
|
have scrolled. The default is zero which means fully transparent, aka invisible.
|
||||||
|
Set to a value between zero and one to see the indicator.''')
|
||||||
|
|
||||||
|
|
||||||
opt('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER',
|
opt('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER',
|
||||||
option_type='to_cmdline',
|
option_type='to_cmdline',
|
||||||
long_text='''
|
long_text='''
|
||||||
|
|||||||
3
kitty/options/parse.py
generated
3
kitty/options/parse.py
generated
@@ -1172,6 +1172,9 @@ class Parser:
|
|||||||
def scrollback_fill_enlarged_window(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def scrollback_fill_enlarged_window(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['scrollback_fill_enlarged_window'] = to_bool(val)
|
ans['scrollback_fill_enlarged_window'] = to_bool(val)
|
||||||
|
|
||||||
|
def scrollback_indicator_opacity(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
|
ans['scrollback_indicator_opacity'] = unit_float(val)
|
||||||
|
|
||||||
def scrollback_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def scrollback_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['scrollback_lines'] = scrollback_lines(val)
|
ans['scrollback_lines'] = scrollback_lines(val)
|
||||||
|
|
||||||
|
|||||||
15
kitty/options/to-c-generated.h
generated
15
kitty/options/to-c-generated.h
generated
@@ -135,6 +135,19 @@ convert_from_opts_cursor_stop_blinking_after(PyObject *py_opts, Options *opts) {
|
|||||||
Py_DECREF(ret);
|
Py_DECREF(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_from_python_scrollback_indicator_opacity(PyObject *val, Options *opts) {
|
||||||
|
opts->scrollback_indicator_opacity = PyFloat_AsFloat(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_from_opts_scrollback_indicator_opacity(PyObject *py_opts, Options *opts) {
|
||||||
|
PyObject *ret = PyObject_GetAttrString(py_opts, "scrollback_indicator_opacity");
|
||||||
|
if (ret == NULL) return;
|
||||||
|
convert_from_python_scrollback_indicator_opacity(ret, opts);
|
||||||
|
Py_DECREF(ret);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_from_python_scrollback_pager_history_size(PyObject *val, Options *opts) {
|
convert_from_python_scrollback_pager_history_size(PyObject *val, Options *opts) {
|
||||||
opts->scrollback_pager_history_size = PyLong_AsUnsignedLong(val);
|
opts->scrollback_pager_history_size = PyLong_AsUnsignedLong(val);
|
||||||
@@ -1132,6 +1145,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
|
|||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_cursor_stop_blinking_after(py_opts, opts);
|
convert_from_opts_cursor_stop_blinking_after(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
|
convert_from_opts_scrollback_indicator_opacity(py_opts, opts);
|
||||||
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_scrollback_pager_history_size(py_opts, opts);
|
convert_from_opts_scrollback_pager_history_size(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_scrollback_fill_enlarged_window(py_opts, opts);
|
convert_from_opts_scrollback_fill_enlarged_window(py_opts, opts);
|
||||||
|
|||||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@@ -402,6 +402,7 @@ option_names = ( # {{{
|
|||||||
'resize_debounce_time',
|
'resize_debounce_time',
|
||||||
'resize_in_steps',
|
'resize_in_steps',
|
||||||
'scrollback_fill_enlarged_window',
|
'scrollback_fill_enlarged_window',
|
||||||
|
'scrollback_indicator_opacity',
|
||||||
'scrollback_lines',
|
'scrollback_lines',
|
||||||
'scrollback_pager',
|
'scrollback_pager',
|
||||||
'scrollback_pager_history_size',
|
'scrollback_pager_history_size',
|
||||||
@@ -562,6 +563,7 @@ class Options:
|
|||||||
resize_debounce_time: typing.Tuple[float, float] = (0.1, 0.5)
|
resize_debounce_time: typing.Tuple[float, float] = (0.1, 0.5)
|
||||||
resize_in_steps: bool = False
|
resize_in_steps: bool = False
|
||||||
scrollback_fill_enlarged_window: bool = False
|
scrollback_fill_enlarged_window: bool = False
|
||||||
|
scrollback_indicator_opacity: float = 0
|
||||||
scrollback_lines: int = 2000
|
scrollback_lines: int = 2000
|
||||||
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
|
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
|
||||||
scrollback_pager_history_size: int = 0
|
scrollback_pager_history_size: int = 0
|
||||||
|
|||||||
@@ -594,6 +594,31 @@ draw_tint(bool premult, Screen *screen, const CellRenderData *crd) {
|
|||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
draw_scroll_indicator(bool premult, Screen *screen, const CellRenderData *crd) {
|
||||||
|
if (OPT(scrollback_indicator_opacity) <= 0 || screen->linebuf != screen->main_linebuf || !screen->scrolled_by) return false;
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
if (premult) { BLEND_PREMULT } else { BLEND_ONTO_OPAQUE }
|
||||||
|
bind_program(TINT_PROGRAM);
|
||||||
|
const color_type bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
|
||||||
|
GLfloat alpha = 0.8f;
|
||||||
|
float frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
|
||||||
|
const GLfloat bar_height = crd->gl.dy;
|
||||||
|
GLfloat bottom = (crd->gl.ystart - crd->gl.height);
|
||||||
|
bottom += MAX(0, crd->gl.height - bar_height) * frac;
|
||||||
|
#define C(shift) srgb_color((bar_color >> shift) & 0xFF) * premult_factor
|
||||||
|
GLfloat premult_factor = premult ? alpha : 1.0f;
|
||||||
|
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), alpha);
|
||||||
|
#undef C
|
||||||
|
GLfloat width = 0.5f * crd->gl.dx;
|
||||||
|
GLfloat left = (GLfloat)(crd->gl.xstart + (screen->columns * crd->gl.dx - width));
|
||||||
|
glUniform4f(tint_program_layout.uniforms.edges, left, bottom, left + width, bottom + bar_height);
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static float prev_inactive_text_alpha = -1;
|
static float prev_inactive_text_alpha = -1;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -972,14 +997,16 @@ draw_cells(ssize_t vao_idx, const WindowRenderData *srd, OSWindow *os_window, bo
|
|||||||
scale_rendered_graphic(grman->render_data.item + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio);
|
scale_rendered_graphic(grman->render_data.item + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool use_premult = false;
|
||||||
has_underlying_image |= grman->num_of_below_refs > 0 || grman->num_of_negative_refs > 0;
|
has_underlying_image |= grman->num_of_below_refs > 0 || grman->num_of_negative_refs > 0;
|
||||||
if (os_window->is_semi_transparent) {
|
if (os_window->is_semi_transparent) {
|
||||||
if (has_underlying_image) draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, wl);
|
if (has_underlying_image) { draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, wl); use_premult = true; }
|
||||||
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
|
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
|
||||||
} else {
|
} else {
|
||||||
if (has_underlying_image) draw_cells_interleaved(vao_idx, screen, os_window, &crd, wl);
|
if (has_underlying_image) draw_cells_interleaved(vao_idx, screen, os_window, &crd, wl);
|
||||||
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
|
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
|
||||||
}
|
}
|
||||||
|
draw_scroll_indicator(use_premult, screen, &crd);
|
||||||
|
|
||||||
if (screen->start_visual_bell_at) {
|
if (screen->start_visual_bell_at) {
|
||||||
GLfloat intensity = get_visual_bell_intensity(screen);
|
GLfloat intensity = get_visual_bell_intensity(screen);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ typedef struct {
|
|||||||
float macos_thicken_font;
|
float macos_thicken_font;
|
||||||
WindowTitleIn macos_show_window_title_in;
|
WindowTitleIn macos_show_window_title_in;
|
||||||
char *bell_path, *bell_theme;
|
char *bell_path, *bell_theme;
|
||||||
float background_opacity, dim_opacity;
|
float background_opacity, dim_opacity, scrollback_indicator_opacity;
|
||||||
float text_contrast, text_gamma_adjustment;
|
float text_contrast, text_gamma_adjustment;
|
||||||
bool text_old_gamma;
|
bool text_old_gamma;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user