Files
wash ad8b284869 runtime: implement an extensible line editor
the line editor supports custom keybinds and data storage, allowing for
a wide range of functionality to be implemented via plugins.

included plugins include:
* core: basic input and cursor movement.
* history: input history storage and retrieval (unfinished)
* highlight: support for colour-highlighting the line buffer (unfinished)
* syntax: parses the line buffer and uses `highlight` to apply syntax highlighting (unfinished).
* shell-integration:
  - allows a `prompt` function to be defined, which will be called to get the text to
    be used for the prompt
  - exposes key properties of the line editor to the shell environment, allowing line editor
    functionality to be extended via shell scripts.
2026-06-20 15:13:34 +01:00

106 lines
2.0 KiB
C

#include "line-editor.h"
#include <fx/encoding.h>
static void convert_offset_to_xy(
struct bshell_line_ed_p *ed,
unsigned long offset,
unsigned long *out_x,
unsigned long *out_y)
{
unsigned long x = 0, y = 0;
unsigned int w = 0, h = 0;
fx_tty_get_dimensions(ed->ed_tty, &w, &h);
if (!w || !h) {
w = 80;
h = 25;
}
fx_string *prompt = line_ed_get_prompt(ed);
fx_string *buffer = line_ed_get_buffer(ed);
const char *s = fx_string_get_cstr(prompt);
size_t len = fx_string_get_size(prompt, FX_STRLEN_CODEPOINTS);
fx_wchar prev = FX_WCHAR_INVALID;
for (unsigned long i = 0; i < len; i++) {
fx_wchar c = fx_wchar_utf8_codepoint_decode(s);
if (prev != FX_WCHAR_INVALID) {
if (prev == '\n' || x + 1 >= w) {
x = 0;
y++;
} else {
x += line_ed_get_char_width(c);
}
}
unsigned int stride = fx_wchar_utf8_codepoint_size(c);
if (stride == 0) {
break;
}
s += stride;
prev = c;
}
s = fx_string_get_cstr(buffer);
len = fx_string_get_size(buffer, FX_STRLEN_CODEPOINTS);
for (unsigned long i = 0; i < offset && i < len; i++) {
fx_wchar c = fx_wchar_utf8_codepoint_decode(s);
if (prev != FX_WCHAR_INVALID) {
if (prev == '\n' || x + 1 >= w) {
x = 0;
y++;
} else {
x += line_ed_get_char_width(c);
}
}
unsigned int stride = fx_wchar_utf8_codepoint_size(c);
if (stride == 0) {
break;
}
s += stride;
prev = c;
}
if (offset > len) {
if (x + 1 >= w) {
x = 0;
y++;
} else {
x++;
}
}
if (out_x) {
*out_x = x;
}
if (out_y) {
*out_y = y;
}
}
void line_ed_get_points(struct bshell_line_ed_p *ed, struct cursor_points *out)
{
unsigned long cursor = line_ed_get_cursor(ed);
fx_string *buffer = line_ed_get_buffer(ed);
convert_offset_to_xy(
ed,
cursor + 1,
&out->c_cursor_x,
&out->c_cursor_y);
convert_offset_to_xy(
ed,
fx_string_get_size(buffer, FX_STRLEN_CODEPOINTS),
&out->c_render_limit_x,
&out->c_render_limit_y);
convert_offset_to_xy(
ed,
fx_string_get_size(buffer, FX_STRLEN_CODEPOINTS) + 1,
&out->c_cursor_limit_x,
&out->c_cursor_limit_y);
}