add copy, start on paste and text selections

This commit is contained in:
Matthew 2025-10-05 20:02:44 +11:00
parent 70f51642cd
commit 342e342a50
5 changed files with 156 additions and 29 deletions

@ -1 +1 @@
Subproject commit 2af4a293148aadac84d9fec3505d2adcdb747298 Subproject commit 92c4f8eb665e9fc7a58dc9631bb6f26a0828a638

View File

@ -15,12 +15,26 @@ struct FlatBuffer
LineStart[] line_starts; LineStart[] line_starts;
u64 length; u64 length;
u64 lf_count; u64 lf_count;
i64 buf_pos; i64 buf_pos;
i64 offset; i64 offset;
i64 rows; i64 rows;
I64Vec2 sel;
SelectMode sel_mode;
bool dirty; bool dirty;
} }
enum SelectMode
{
None,
Normal,
Line,
}
alias SM = SelectMode;
struct LineStart struct LineStart
{ {
u64 pos; u64 pos;
@ -98,6 +112,7 @@ CreateFlatBuffer(u8[] data)
data: buf, data: buf,
length: cast(u64)data.length, length: cast(u64)data.length,
lf_count: CountLF(data), lf_count: CountLF(data),
sel: -1,
}; };
fb.tk = CreateTokenizer(&fb); fb.tk = CreateTokenizer(&fb);
@ -277,7 +292,42 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos)
Reset(&fb.arena); Reset(&fb.arena);
AdjustOffset(fb); UpdateOffset(fb);
}
void
ToggleSelection(FlatBuffer* fb, SelectMode mode)
{
if(fb.sel_mode == SM.None)
{
StartSelection(fb, mode);
}
else
{
EndSelection(fb);
}
}
void
StartSelection(FlatBuffer* fb, SelectMode mode)
{
fb.sel_mode = mode;
if(mode == SM.Normal)
{
fb.sel = fb.buf_pos;
}
else if(mode == SM.Line)
{
fb.sel = CurrentLine(fb);
}
}
void
EndSelection(FlatBuffer* fb)
{
fb.sel = -1;
fb.sel_mode = SM.None;
} }
void void
@ -790,14 +840,30 @@ Move(FlatBuffer* fb, Input key, Modifier md)
} }
} }
AdjustOffset(fb); UpdateOffset(fb);
U64Vec2 p = VecPos(fb); UpdateSelection(fb);
Logf("selection %s", fb.sel.v);
return taken; return taken;
} }
void void
AdjustOffset(FlatBuffer* fb) UpdateSelection(FlatBuffer* fb)
{
if(fb.sel_mode == SM.Normal)
{
fb.sel.y = fb.buf_pos;
}
if(fb.sel_mode == SM.Line)
{
fb.sel.y = CurrentLine(fb);
}
}
void
UpdateOffset(FlatBuffer* fb)
{ {
if(fb.rows > 0) with(fb) if(fb.rows > 0) with(fb)
{ {

View File

@ -22,6 +22,7 @@ debug bool g_frame_continue = false;
struct EditorCtx struct EditorCtx
{ {
Arena arena; Arena arena;
PlatformWindow* window;
UIPanel* base_panel; UIPanel* base_panel;
u64 panel_id; u64 panel_id;
EditState state; EditState state;
@ -61,6 +62,23 @@ struct Editor
u64 line_offset; u64 line_offset;
} }
struct ChangeStacks
{
Arena arena;
u64 current_pos;
u8[] current_str;
u64 current_len;
EditorChange* undos;
EditorChange* redos;
}
struct EditorChange
{
u8[] str;
u64 pos;
EditorChange* next;
}
struct Command struct Command
{ {
u8[] name; u8[] name;
@ -79,6 +97,8 @@ enum CmdType
OpenFile, OpenFile,
SaveFile, SaveFile,
CreateFile, CreateFile,
VSplit,
HSplit,
} }
alias CT = CmdType; alias CT = CmdType;
@ -148,6 +168,7 @@ InitEditorCtx(PlatformWindow* window)
InitUICtx(window); InitUICtx(window);
EditorCtx ctx = { EditorCtx ctx = {
window: window,
arena: CreateArena(MB(2)), arena: CreateArena(MB(2)),
cmd: { cmd: {
arena: CreateArena(MB(1)), arena: CreateArena(MB(1)),
@ -473,6 +494,9 @@ Shift(Modifier md)
void void
HandleInputs(EditorCtx* ctx, Inputs* inputs) HandleInputs(EditorCtx* ctx, Inputs* inputs)
{ {
u8[] cb_text;
FlatBuffer* fb = !Nil(GetFocusedPanel()) ? &(GetFocusedPanel()).ed.buf : null;
for(auto node = inputs.list.first; node != null; node = node.next) for(auto node = inputs.list.first; node != null; node = node.next)
{ {
bool taken = false; bool taken = false;
@ -480,7 +504,6 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
Input key = node.value.key; Input key = node.value.key;
Modifier md = node.value.md; Modifier md = node.value.md;
bool pressed = node.value.pressed; bool pressed = node.value.pressed;
FlatBuffer* fb = !Nil(GetFocusedPanel()) ? &(GetFocusedPanel()).ed.buf : null;
if (pressed) if (pressed)
{ {
@ -529,8 +552,18 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
} break; } break;
case v: case v:
{ {
AddEditor(ctx, GetFocusedPanel(), A2D.X); if(Ctrl(md))
taken = true; {
cb_text = ClipboardText(ctx.window);
}
if(Shift(md))
{
ToggleSelection(fb, SM.Line);
}
else
{
ToggleSelection(fb, SM.Normal);
}
} break; } break;
case c: case c:
{ {
@ -566,6 +599,11 @@ HandleInputs(EditorCtx* ctx, Inputs* inputs)
} }
InsertInputToBuf(ctx); InsertInputToBuf(ctx);
if(cb_text.length > 0)
{
Insert(fb, cb_text, cb_text.length);
}
} }
void void
@ -721,6 +759,14 @@ GetCommands(CmdPalette* cmd)
name: CastStr!(u8)("create"), name: CastStr!(u8)("create"),
type: CT.CreateFile, type: CT.CreateFile,
}, },
{
name: CastStr!(u8)("vsplit"),
type: CT.VSplit,
},
{
name: CastStr!(u8)("hsplit"),
type: CT.HSplit,
},
]; ];
Reset(&cmd.arena); Reset(&cmd.arena);
@ -770,16 +816,24 @@ HandleCmdMode(EditorCtx* ctx, InputEvent ev)
{ {
case Enter: case Enter:
{ {
if(cmd.current.type == CT.None) if(cmd.current.type == CT.None && cmd.commands.length > 0)
{ {
goto case Tab; if(cmd.commands[cmd.selected].type == CT.OpenFile)
{
goto case Tab;
}
else
{
cmd.current = cmd.commands[cmd.selected];
}
} }
UIPanel* p = GetFocusedPanel();
switch(cmd.current.type) switch(cmd.current.type)
{ {
case CT.OpenFile: case CT.OpenFile:
{ {
UIPanel* p = GetFocusedPanel();
if(!Nil(p) && cmd.selected >= 0 && cmd.selected < cmd.opt_strs.length) if(!Nil(p) && cmd.selected >= 0 && cmd.selected < cmd.opt_strs.length)
{ {
OpenFile(p.ed, cmd.opt_strs[cmd.selected]); OpenFile(p.ed, cmd.opt_strs[cmd.selected]);
@ -787,12 +841,15 @@ HandleCmdMode(EditorCtx* ctx, InputEvent ev)
} break; } break;
case CT.SaveFile: case CT.SaveFile:
{ {
UIPanel* p = GetFocusedPanel();
if(!Nil(p)) if(!Nil(p))
{ {
SaveFile(p.ed, GetParam(cmd)); SaveFile(p.ed, GetParam(cmd));
} }
} break; } break;
case CT.VSplit, CT.HSplit:
{
AddEditor(ctx, p, cmd.current.type == CT.VSplit ? A2D.X : A2D.Y);
} break;
default: break; default: break;
} }
@ -800,14 +857,9 @@ HandleCmdMode(EditorCtx* ctx, InputEvent ev)
} goto CmdInputEnd; } goto CmdInputEnd;
case Backspace: case Backspace:
{ {
if(cmd.icount > 0) if(CondIncr!(-1)(cmd.icount > 0, &cmd.icount) && cmd.buffer[cmd.icount] == ' ')
{ {
cmd.icount -= 1; cmd.current = cast(Command)NO_CMD;
if(cmd.buffer[cmd.icount] == ' ')
{
cmd.current = cast(Command)NO_CMD;
}
} }
} break; } break;
case Space: case Space:
@ -827,17 +879,11 @@ HandleCmdMode(EditorCtx* ctx, InputEvent ev)
} break; } break;
case Up: case Up:
{ {
if(cmd.selected > 0) CondIncr!(-1)(cmd.selected > 0, &cmd.selected);
{
cmd.selected -= 1;
}
} break; } break;
case Down: case Down:
{ {
if(cmd.selected < cmd.opt_strs.length-1) CondIncr!(+1)(cmd.selected < cmd.opt_strs.length-1, &cmd.selected);
{
cmd.selected += 1;
}
} break; } break;
mixin(TextLineCharCases()); mixin(TextLineCharCases());
default: break; default: break;

View File

@ -129,6 +129,7 @@ struct UICtx
UIStack!(f32)* edge_softness; UIStack!(f32)* edge_softness;
i64 highlighted_char; i64 highlighted_char;
I64Vec2 selected;
u32 tab_width; u32 tab_width;
f32 text_size; f32 text_size;
@ -176,6 +177,7 @@ struct UIItem
UISize[2] size_info; UISize[2] size_info;
Vec2 adjustment; Vec2 adjustment;
i64 highlighted_char; i64 highlighted_char;
I64Vec2 selected;
// Calculated Parameters // Calculated Parameters
Vec4[4] color; Vec4[4] color;

View File

@ -378,8 +378,17 @@ EditorView(UIPanel* panel)
Container(ScratchName(panel.id, "lines"), UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0), A2D.Y); Container(ScratchName(panel.id, "lines"), UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0), A2D.Y);
{ {
U64Vec2 pos = VecPos(&ed.buf); I64Vec2 sel = ed.buf.sel;
u64 i = 0; if(sel.x > sel.y)
{
i64 t = sel.y;
sel.y = sel.x;
sel.x = t;
}
U64Vec2 pos = VecPos(&ed.buf);
SelectMode sm = ed.buf.sel_mode;
u64 i = 0;
for(LineBuffer* buf = ed.linebufs.first; buf != null; buf = buf.next, i += 1) for(LineBuffer* buf = ed.linebufs.first; buf != null; buf = buf.next, i += 1)
{ {
if(buf == ed.linebufs.first) if(buf == ed.linebufs.first)
@ -395,6 +404,10 @@ EditorView(UIPanel* panel)
Push!("highlighted_char")(pos.x); Push!("highlighted_char")(pos.x);
} }
if(sm == SM.Line && line_no >= sel.x && line_no <= sel.y)
{
}
TextPart* tp = WrappedTextLine(buf.text, panel.id, text_size, line_no, buf.style); TextPart* tp = WrappedTextLine(buf.text, panel.id, text_size, line_no, buf.style);
height += (text_size * tp.count); height += (text_size * tp.count);
if(TextClicked(tp)) if(TextClicked(tp))