home and end

This commit is contained in:
Alessandro Mauri 2025-10-20 23:37:36 +02:00
parent fe6f32c769
commit be51e37231
3 changed files with 61 additions and 18 deletions

View File

@ -44,11 +44,13 @@ bitstruct ModKeys : uint {
bool scroll : 11; bool scroll : 11;
bool bkspc : 12; bool bkspc : 12;
bool del : 13; bool del : 13;
bool home : 14;
bool end : 15;
// arrow keys // arrow keys
bool up : 14; bool up : 16;
bool down : 15; bool down : 17;
bool left : 16; bool left : 18;
bool right : 17; bool right : 19;
} }
const ModKeys KMOD_CTRL = {.lctrl = true, .rctrl = true}; const ModKeys KMOD_CTRL = {.lctrl = true, .rctrl = true};

View File

@ -10,8 +10,10 @@ struct TextEdit {
} }
fn String TextEdit.to_string(&te) => (String)te.buffer[:te.chars]; fn String TextEdit.to_string(&te) => (String)te.buffer[:te.chars];
fn String TextEdit.until_cursor(&te) => (String)te.buffer[:te.cursor]; fn String TextEdit.until_cursor(&te) => (String)te.buffer[..te.cursor];
fn String TextEdit.from_cursor(&te) => (String)te.buffer[te.cursor..]; fn String TextEdit.from_cursor(&te) => (String)te.buffer[te.cursor..te.chars];
fn String TextEdit.until(&te, usz off) => (String)te.buffer[..min(te.chars, off)];
fn String TextEdit.from(&te, usz off) => (String)te.buffer[off..te.chars];
// implement text editing operations on the buffer // implement text editing operations on the buffer
// returns true if the buffer is full // returns true if the buffer is full
@ -22,17 +24,19 @@ fn bool Ctx.text_edit(&ctx, TextEdit* te)
te.insert_utf8(in); te.insert_utf8(in);
bool select = !!(mod & KMOD_SHIFT);
bool ctrl = !!(mod & KMOD_CTRL);
// handle backspace and delete // handle backspace and delete
if (mod.bkspc) { if (mod.bkspc) {
if (mod & KMOD_CTRL) { if (ctrl) {
te.remove_word(false); te.remove_word(false);
} else { } else {
te.remove_character(false); te.remove_character(false);
} }
} }
if (mod.del) { if (mod.del) {
if (mod & KMOD_CTRL) { if (ctrl) {
te.remove_word(true); te.remove_word(true);
} else { } else {
te.remove_character(true); te.remove_character(true);
@ -41,23 +45,29 @@ fn bool Ctx.text_edit(&ctx, TextEdit* te)
// handle arrow keys // handle arrow keys
if (mod.left) { if (mod.left) {
if (mod & KMOD_CTRL) { if (ctrl) {
te.move_cursor_word(false, !!(mod & KMOD_SHIFT)); te.move_cursor_word(false, select);
} else { } else {
te.move_cursor(false, !!(mod & KMOD_SHIFT)); te.move_cursor(false, select);
} }
} }
if (mod.right) { if (mod.right) {
if (mod & KMOD_CTRL) { if (ctrl) {
te.move_cursor_word(true, !!(mod & KMOD_SHIFT)); te.move_cursor_word(true, select);
} else { } else {
te.move_cursor(true, !!(mod & KMOD_SHIFT)); te.move_cursor(true, select);
} }
} }
if (mod.home) {
te.set_cursor(te.search_lines(false).first, select);
}
if (mod.end) {
te.set_cursor(te.search_lines(true).first, select);
}
// TODO: up, down // TODO: up, down
// TODO: mod.home
// TODO: mod.end
return te.chars < te.buffer.len; return te.chars < te.buffer.len;
} }
@ -66,6 +76,9 @@ module ugui::textedit::te;
import std::core::string; import std::core::string;
import std::ascii; import std::ascii;
import std::collections::pair;
alias OffPair = pair::Pair{usz, usz};
// returns the offset of the next codepoint in the buffer from the cursor // returns the offset of the next codepoint in the buffer from the cursor
fn usz TextEdit.next_char_off(&te) fn usz TextEdit.next_char_off(&te)
@ -160,6 +173,32 @@ fn void TextEdit.move_cursor_word(&te, bool forward, bool select)
if (prev_cur == te.cursor) te.move_cursor(forward, select); if (prev_cur == te.cursor) te.move_cursor(forward, select);
} }
// get the offset of the current line start and the previous line start from the cursor
fn OffPair TextEdit.search_lines(&te, bool forward)
{
// look for the current line start
OffPair p;
if (forward) {
// if searching forwards look for the end of the current line and the end of the next line
p.first = te.cursor + (te.from_cursor().index_of_char('\n') ?? (te.chars - te.cursor));
if (p.first < te.chars) {
p.second = p.first + 1 + (te.from(p.first + 1).index_of_char('\n') ?? (te.chars - p.first - 1));
} else {
p.second = te.chars;
}
} else {
// if searching backwards, look for the start of the current and previous line
if (te.cursor > 0) {
p.first = te.until(te.cursor-1).rindex_of_char('\n') ?? 0;
if (p.first != 0 && te.chars) p.first++;
}
p.second = te.until(p.first).rindex_of_char('\n') ?? 0;
}
return p;
}
fn void TextEdit.delete_selection(&te) fn void TextEdit.delete_selection(&te)
{ {
if (te.sel_len == 0) return; if (te.sel_len == 0) return;

View File

@ -155,6 +155,8 @@ fn int main(String[] args)
mod.lshift = e.key.key == K_LSHIFT ? !!(e.type == EVENT_KEY_DOWN) : mod.lshift; mod.lshift = e.key.key == K_LSHIFT ? !!(e.type == EVENT_KEY_DOWN) : mod.lshift;
mod.bkspc = e.key.key == K_BACKSPACE ? !!(e.type == EVENT_KEY_DOWN) : mod.bkspc; mod.bkspc = e.key.key == K_BACKSPACE ? !!(e.type == EVENT_KEY_DOWN) : mod.bkspc;
mod.del = e.key.key == K_DELETE ? !!(e.type == EVENT_KEY_DOWN) : mod.del; mod.del = e.key.key == K_DELETE ? !!(e.type == EVENT_KEY_DOWN) : mod.del;
mod.home = e.key.key == K_HOME ? !!(e.type == EVENT_KEY_DOWN) : mod.home;
mod.end = e.key.key == K_END ? !!(e.type == EVENT_KEY_DOWN) : mod.end;
mod.up = e.key.key == K_UP ? !!(e.type == EVENT_KEY_DOWN) : mod.up; mod.up = e.key.key == K_UP ? !!(e.type == EVENT_KEY_DOWN) : mod.up;
mod.down = e.key.key == K_DOWN ? !!(e.type == EVENT_KEY_DOWN) : mod.down; mod.down = e.key.key == K_DOWN ? !!(e.type == EVENT_KEY_DOWN) : mod.down;
mod.left = e.key.key == K_LEFT ? !!(e.type == EVENT_KEY_DOWN) : mod.left; mod.left = e.key.key == K_LEFT ? !!(e.type == EVENT_KEY_DOWN) : mod.left;