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;
u64 length;
u64 lf_count;
i64 buf_pos;
i64 offset;
i64 rows;
I64Vec2 sel;
SelectMode sel_mode;
bool dirty;
}
enum SelectMode
{
None,
Normal,
Line,
}
alias SM = SelectMode;
struct LineStart
{
u64 pos;
@ -98,6 +112,7 @@ CreateFlatBuffer(u8[] data)
data: buf,
length: cast(u64)data.length,
lf_count: CountLF(data),
sel: -1,
};
fb.tk = CreateTokenizer(&fb);
@ -277,7 +292,42 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos)
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
@ -790,14 +840,30 @@ Move(FlatBuffer* fb, Input key, Modifier md)
}
}
AdjustOffset(fb);
U64Vec2 p = VecPos(fb);
UpdateOffset(fb);
UpdateSelection(fb);
Logf("selection %s", fb.sel.v);
return taken;
}
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)
{

View File

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

View File

@ -129,6 +129,7 @@ struct UICtx
UIStack!(f32)* edge_softness;
i64 highlighted_char;
I64Vec2 selected;
u32 tab_width;
f32 text_size;
@ -176,6 +177,7 @@ struct UIItem
UISize[2] size_info;
Vec2 adjustment;
i64 highlighted_char;
I64Vec2 selected;
// Calculated Parameters
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);
{
U64Vec2 pos = VecPos(&ed.buf);
u64 i = 0;
I64Vec2 sel = ed.buf.sel;
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)
{
if(buf == ed.linebufs.first)
@ -395,6 +404,10 @@ EditorView(UIPanel* panel)
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);
height += (text_size * tp.count);
if(TextClicked(tp))