some code clean up, readme updated
This commit is contained in:
parent
8e74e90109
commit
d133fc90b6
BIN
media/animated-cursor.gif
Normal file
BIN
media/animated-cursor.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 841 KiB |
BIN
media/command-palette.gif
Normal file
BIN
media/command-palette.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 MiB |
BIN
media/editor-demo.mp4
Normal file
BIN
media/editor-demo.mp4
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 166 KiB |
BIN
media/editor.png
BIN
media/editor.png
Binary file not shown.
|
Before Width: | Height: | Size: 226 KiB |
Binary file not shown.
Binary file not shown.
BIN
media/panels.gif
Normal file
BIN
media/panels.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 MiB |
BIN
media/text-input.gif
Normal file
BIN
media/text-input.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 303 KiB |
24
readme.md
24
readme.md
@ -1,24 +1,30 @@
|
||||
# ScratchPad
|
||||
A text editor I'm developing for personal use as well as getting used to 2D development with Vulkan.
|
||||
A text editor I'm developing for personal use as well as getting used to 2D and UI development with Vulkan.
|
||||
|
||||
It's currently in an early state, functionality isn't entirely implemented for what you would expect for a text editor and it currently only works on Linux and x86 due to the platform layer only supporting Linux/X11 and inline assembly being used respectively. Will eventually also implement the platform layer for Windows.
|
||||
It's currently in an early state but has core functionality built out and I'm currently in the process of building out functionality
|
||||
|
||||
## Details
|
||||
|
||||
- UI auto layout implementation that can handle resizable panels, text wrapping, windows and more
|
||||
- Command palette for actions and eventually more such as config options
|
||||
- Editor that supports multiple text buffers through multiple panels that can be automatically resized and arbitrarily split
|
||||
- Command palette for actions such as opening/saving files, splitting text editor views and eventually will contain config options and key bindings.
|
||||
- Implemented with minimal external dependencies, only using cglm/xxhash/Vulkan Memory Allocator as well as system libraries and Vulkan for the graphics API
|
||||
- Manual memory management primarily using arenas, no GC usage.
|
||||
- Syntax highlighting (for D and C-like languages) and auto indenting/auto closing pairs (strings, braces, etc)
|
||||
- Animations such as smooth scrolling, highlighting on focus and animated cursors with text after the cursor having its position animated
|
||||
|
||||
## Showcase
|
||||
|
||||
### Videos
|
||||
### Gifs
|
||||
|
||||
https://git.sleepy.day/sleepy-day/editor/raw/branch/master/media/features.mp4
|
||||

|
||||
|
||||
https://git.sleepy.day/sleepy-day/editor/raw/branch/master/media/indents.mp4
|
||||

|
||||
|
||||
### Screenshot
|
||||

|
||||
|
||||

|
||||
|
||||
### Demonstration Video
|
||||
|
||||
https://git.sleepy.day/sleepy-day/editor/raw/branch/master/media/editor-demo.mp4
|
||||
|
||||

|
||||
|
||||
2
src/dlib
2
src/dlib
@ -1 +1 @@
|
||||
Subproject commit 246e7006f535f65e0d045c644bfa8d645c86f5f7
|
||||
Subproject commit 53dbb8bf3492f99418f129d54184d8eddc895338
|
||||
@ -145,6 +145,7 @@ Init(FlatBuffer* fb, u8[] data, string file_name)
|
||||
fb.selection = -1;
|
||||
fb.sel_mode = SM.None;
|
||||
fb.linebufs = CreateLineBuffers(MB(1));
|
||||
fb.pos = 0;
|
||||
|
||||
SetBuffers(fb, buf);
|
||||
|
||||
@ -477,6 +478,13 @@ SliceLineBuffer(FlatBuffer* fb, Line* ls)
|
||||
return lbuf;
|
||||
}
|
||||
|
||||
void
|
||||
Clear(Editor* ed)
|
||||
{
|
||||
Change(&ed.buf, [], "");
|
||||
ed.line_offset = 0;
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
ResetBuffer(FlatBuffer* fb)
|
||||
{
|
||||
|
||||
@ -7,7 +7,6 @@ import buffer;
|
||||
import ui : Nil;
|
||||
import ui;
|
||||
import parsing;
|
||||
import views;
|
||||
|
||||
import std.algorithm.comparison : clamp;
|
||||
import std.format;
|
||||
@ -50,13 +49,16 @@ struct Ctx
|
||||
u64 frame;
|
||||
u64 f_idx;
|
||||
|
||||
Notification* active_notifications;
|
||||
Notification* free_notifications;
|
||||
|
||||
LinkedList!(UIInput) events;
|
||||
IVec2 mouse_pos;
|
||||
|
||||
FontFace font;
|
||||
FontGlyphs[FS] glyph_sets;
|
||||
u32 glyph_sets_used;
|
||||
bool[FO] glyphs_to_load;
|
||||
FontSet[FS] font_sets;
|
||||
u32 font_sets_used;
|
||||
bool[FO] fonts_to_load;
|
||||
bool prev_has_tex;
|
||||
u32 prev_atlas_index;
|
||||
|
||||
@ -71,6 +73,7 @@ struct Ctx
|
||||
|
||||
UIPanel* base_panel;
|
||||
UIPanel* focused_panel;
|
||||
UIPanel* free_panels;
|
||||
|
||||
u64 last_hover_frame;
|
||||
|
||||
@ -95,6 +98,14 @@ struct Ctx
|
||||
alias rd_ctx this;
|
||||
}
|
||||
|
||||
struct Notification
|
||||
{
|
||||
Notification* next;
|
||||
string message;
|
||||
f32 anim_progress = 0.0;
|
||||
f32 elapsed = 0.0;
|
||||
}
|
||||
|
||||
struct TextInputBuffer
|
||||
{
|
||||
u8[] data;
|
||||
@ -128,6 +139,8 @@ struct Editor
|
||||
i64 line_offset;
|
||||
i64 line_height;
|
||||
|
||||
Editor* free_next;
|
||||
|
||||
alias buf this;
|
||||
}
|
||||
|
||||
@ -218,15 +231,24 @@ enum EditState
|
||||
SetPanelFocus, // if moving left/right move up parent tree until one is found with a2d.x, same thing for up/down a2d.y
|
||||
} alias ES = EditState;
|
||||
|
||||
__gshared bool g_input_mode = false;
|
||||
__gshared Ctx g_ctx;
|
||||
__gshared const Editor g_nil_ed;
|
||||
__gshared Editor* g_NIL_ED;
|
||||
__gshared const UIItem g_ui_nil_item;
|
||||
__gshared UIItem* g_UI_NIL;
|
||||
__gshared const UIInput g_ui_nil_input;
|
||||
__gshared UIInput* g_UI_NIL_INPUT;
|
||||
__gshared const UIPanel g_nil_panel;
|
||||
__gshared UIPanel* g_NIL_PANEL;
|
||||
__gshared const Notification g_nil_notif;
|
||||
__gshared Notification* g_NIL_NOTIF;
|
||||
|
||||
const Command NO_CMD = {
|
||||
name: [],
|
||||
type: CT.None,
|
||||
};
|
||||
|
||||
Command[20] CMD_LIST = [
|
||||
Command[21] CMD_LIST = [
|
||||
{
|
||||
name: "Open",
|
||||
cmd: "open",
|
||||
@ -239,7 +261,7 @@ Command[20] CMD_LIST = [
|
||||
cmd: "save",
|
||||
desc: "Save the current file in the focused editor view.",
|
||||
type: CT.Callback,
|
||||
fn: &NotImplementedCallback,
|
||||
fn: &SaveFileWindow,
|
||||
},
|
||||
{
|
||||
name: "New File",
|
||||
@ -262,6 +284,13 @@ Command[20] CMD_LIST = [
|
||||
type: CT.Callback,
|
||||
fn: &SplitHorizontally,
|
||||
},
|
||||
{
|
||||
name: "Close Panel",
|
||||
cmd: "close",
|
||||
desc: "Close the currently highlighted panel, if it's the last panel it will have the file closed instead.",
|
||||
type: CT.Callback,
|
||||
fn: &ClosePanelCmd,
|
||||
},
|
||||
{
|
||||
name: "Test Option 1",
|
||||
cmd: "testopt1",
|
||||
@ -369,6 +398,59 @@ Command[20] CMD_LIST = [
|
||||
},
|
||||
];
|
||||
|
||||
bool
|
||||
ClosePanelCmd(Ctx* ctx)
|
||||
{
|
||||
Clear(ctx.focused_panel.ed);
|
||||
if(ctx.focused_panel != ctx.base_panel)
|
||||
{
|
||||
DLLRemove(ctx.focused_panel.parent, ctx.focused_panel, g_NIL_PANEL);
|
||||
|
||||
u64 child_count;
|
||||
UIPanel* removed = ctx.focused_panel;
|
||||
UIPanel* parent = removed.parent;
|
||||
if(!Nil(parent.first) && parent.first == parent.last)
|
||||
{
|
||||
UIPanel* only_child = parent.first;
|
||||
|
||||
parent.ed = only_child.ed;
|
||||
only_child.ed = null;
|
||||
|
||||
DLLRemove(parent, only_child, g_NIL_PANEL);
|
||||
PushFree(&ctx.free_panels, only_child);
|
||||
|
||||
Focus(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(UIPanel* child = parent.first; !Nil(child); child = child.next)
|
||||
{
|
||||
child_count += 1;
|
||||
}
|
||||
|
||||
f32 add_pct = ctx.focused_panel.pct/child_count;
|
||||
for(UIPanel* child = parent.first; !Nil(child); child = child.next)
|
||||
{
|
||||
child.pct += add_pct;
|
||||
}
|
||||
|
||||
UIPanel* focus = ctx.base_panel;
|
||||
for(UIPanel* panel = ctx.base_panel; true; panel = panel.first)
|
||||
{
|
||||
if(!CheckNil(g_NIL_ED, panel.ed))
|
||||
{
|
||||
Focus(panel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PushFree(&ctx.free_panels, removed);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SplitVertically(Ctx* ctx)
|
||||
{
|
||||
@ -422,7 +504,6 @@ Cycle(Inputs* inputs)
|
||||
ResetScratch(MB(4));
|
||||
|
||||
g_delta = DeltaTime(&g_ctx.timer);
|
||||
g_input_mode = Active(ES.InputMode);
|
||||
|
||||
BeginUI(inputs);
|
||||
|
||||
@ -455,16 +536,22 @@ InitCtx(PlatformWindow* window)
|
||||
{
|
||||
Ctx* ctx = &g_ctx;
|
||||
|
||||
g_NIL_ED = cast(Editor*)&g_nil_ed;
|
||||
g_UI_NIL = cast(UIItem*)&g_ui_nil_item;
|
||||
g_UI_NIL_INPUT = cast(UIInput*)&g_ui_nil_input;
|
||||
g_NIL_PANEL = cast(UIPanel*)&g_nil_panel;
|
||||
|
||||
ctx.window = window;
|
||||
ctx.arena = CreateArena(MB(2));
|
||||
ctx.cmd.text_input.data = Alloc!(u8)(1024);
|
||||
ctx.cmd.exec_cmd_input.data = Alloc!(u8)(1024);
|
||||
ctx.cmd.exec_cmd_arena = CreateArena(MB(1));
|
||||
ctx.timer = CreateTimer();
|
||||
ctx.free_panels = g_NIL_PANEL;
|
||||
|
||||
InitUI(ctx);
|
||||
|
||||
ctx.base_panel = CreatePanel(CreateEditor());
|
||||
ctx.base_panel = CreatePanel();
|
||||
Focus(ctx.base_panel);
|
||||
|
||||
if(getcwd() != "/")
|
||||
@ -505,12 +592,6 @@ GetCtx()
|
||||
return &g_ctx;
|
||||
}
|
||||
|
||||
bool
|
||||
EditModeActive()
|
||||
{
|
||||
return g_input_mode;
|
||||
}
|
||||
|
||||
char[]
|
||||
ToAbsolutePath(string file_name)
|
||||
{
|
||||
@ -648,7 +729,6 @@ Editor*
|
||||
CreateEditor()
|
||||
{
|
||||
Editor* ed = Alloc!(Editor)(&g_ctx.arena);
|
||||
|
||||
ed.arena = CreateArena(MB(4));
|
||||
ed.buf = CreateFlatBuffer([], []);
|
||||
ed.editor_id = g_ctx.editor_id_incr++;
|
||||
@ -656,55 +736,6 @@ CreateEditor()
|
||||
return ed;
|
||||
}
|
||||
|
||||
/*
|
||||
void
|
||||
AddEditor(Panel* target, Axis2D axis)
|
||||
{
|
||||
if(CheckNil(g_NIL_PANEL, target.parent) || target.parent.layout_axis != axis)
|
||||
{
|
||||
Panel* first = CreatePanel(target.ed);
|
||||
Panel* second = CreatePanel(CreateEditor());
|
||||
|
||||
target.layout_axis = axis;
|
||||
target.ed = null;
|
||||
|
||||
DLLPush(target, first, g_NIL_PANEL);
|
||||
DLLPush(target, second, g_NIL_PANEL);
|
||||
|
||||
first.parent = second.parent = target;
|
||||
|
||||
FocusEditor(second);
|
||||
}
|
||||
else if(target.parent.layout_axis == axis)
|
||||
{
|
||||
Panel* panel = CreatePanel(CreateEditor());
|
||||
|
||||
DLLPush(target.parent, target, panel);
|
||||
panel.parent = target.parent;
|
||||
|
||||
UIItem* ed_item = GetEditorItem(panel.ed);
|
||||
/*
|
||||
if(!Nil(ed_item.parent))
|
||||
{
|
||||
u64 count;
|
||||
for(UIItem* c = ed_item.parent.first; !Nil(c); c = c.next)
|
||||
{
|
||||
count += 1;
|
||||
}
|
||||
|
||||
f32 pct = 1.0/cast(f32)count;
|
||||
for(UIItem* c = ed_item.parent.first; !Nil(c); c = c.next)
|
||||
{
|
||||
c.resize_pct = pct;
|
||||
}
|
||||
}
|
||||
* /
|
||||
|
||||
FocusEditor(panel);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pragma(inline) void
|
||||
InsertInputToBuf(Ctx* ctx, Editor* ed)
|
||||
{
|
||||
@ -932,7 +963,7 @@ HandleInputs(UIPanel* p, LinkedList!(UIInput)* inputs, bool hovered, bool focuse
|
||||
{
|
||||
if(hovered)
|
||||
{
|
||||
SetOffset(ed, node.scroll*30);
|
||||
SetOffset(ed, node.scroll*10);
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
@ -1173,6 +1204,7 @@ HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_c
|
||||
{
|
||||
assert(ctx.cmd.cmds[ctx.cmd.selected].fn, "Callback type doesn't have a function pointer set");
|
||||
ctx.state = ES.RunCmd;
|
||||
taken = true;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
@ -1180,14 +1212,7 @@ HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_c
|
||||
else
|
||||
{
|
||||
*enter_hit = true;
|
||||
}
|
||||
} break;
|
||||
case Backspace:
|
||||
{
|
||||
if(text_buffer.length)
|
||||
{
|
||||
text_buffer.length -= 1;
|
||||
*buffer_changed = true;
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
case Up, Down:
|
||||
@ -1196,21 +1221,16 @@ HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_c
|
||||
*selected = (*selected)+incr;
|
||||
|
||||
*selection_changed = true;
|
||||
taken = true;
|
||||
} break;
|
||||
case Escape:
|
||||
{
|
||||
ResetCtx();
|
||||
taken = true;
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
if(ev.text.length)
|
||||
{
|
||||
Check(text_buffer, ev.text.length);
|
||||
text_buffer.data[text_buffer.length .. text_buffer.length+ev.text.length] = cast(u8[])ev.text[0 .. $];
|
||||
text_buffer.length += ev.text.length;
|
||||
|
||||
*buffer_changed = true;
|
||||
}
|
||||
*buffer_changed = taken = HandleTextInput(text_buffer, ev);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
@ -1224,6 +1244,37 @@ HandleCmdMode(Ctx* ctx, bool* enter_hit, bool* buffer_changed, bool* selection_c
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HandleTextInput(TextInputBuffer* text_input, UIInput* ev)
|
||||
{
|
||||
bool taken;
|
||||
|
||||
switch(ev.key) with(Input)
|
||||
{
|
||||
case Backspace:
|
||||
{
|
||||
if(text_input.length)
|
||||
{
|
||||
text_input.length -= 1;
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
if(ev.text.length)
|
||||
{
|
||||
Check(text_input, ev.text.length);
|
||||
text_input.data[text_input.length .. text_input.length+ev.text.length] = cast(u8[])ev.text[0 .. $];
|
||||
text_input.length += ev.text.length;
|
||||
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return taken;
|
||||
}
|
||||
|
||||
pragma(inline) void
|
||||
Check(TextInputBuffer* text_buffer, u64 length)
|
||||
{
|
||||
|
||||
@ -169,6 +169,8 @@ const TokenStyle[TT.max] TOKEN_STYLES = [
|
||||
TT.Comment: TS.Comment,
|
||||
];
|
||||
|
||||
// Bad idea vvv
|
||||
|
||||
const TT[128] D_STD_TOKEN = [
|
||||
'$': TT.Dollar,
|
||||
'(': TT.LeftParen,
|
||||
@ -190,7 +192,6 @@ const TT[128] D_OP_TOKEN = [
|
||||
'^': TT.Caret,
|
||||
'&': TT.Ampersand,
|
||||
'*': TT.Asterisk,
|
||||
'/': TT.Slash,
|
||||
'-': TT.Minus,
|
||||
'=': TT.Equals,
|
||||
'+': TT.Plus,
|
||||
|
||||
589
src/editor/ui.d
589
src/editor/ui.d
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
import dlib;
|
||||
import ui;
|
||||
import ui : YELLOW, BLUE, RED;
|
||||
import editor;
|
||||
import parsing;
|
||||
import buffer;
|
||||
|
||||
import std.algorithm.comparison : clamp;
|
||||
import std.format;
|
||||
import std.conv;
|
||||
|
||||
__gshared const Editor g_nil_ed;
|
||||
__gshared Editor* g_NIL_ED;
|
||||
|
||||
/******
|
||||
- Set up "themes" for different components (e.g. command palette window, editor view, status bar) then have the ability to create styles and apply them to different sections via a string lookup, e.g. start of function to draw cmd palette call ApplyTheme(selected_theme_name) then do code to draw things, get to options and call ApplyTheme(selected_theme_name_for_options), etc.
|
||||
- Move scrolling behaviour into ui.d and externally be oblivious to it, e.g. just feed it all lines of text in a text buffer, will have to specifically handle extreme cases later but initially i think it should be fine
|
||||
******/
|
||||
|
||||
const f32 CMD_X_PAD = 8.0;
|
||||
const f32 CMD_Y_PAD = 4.0;
|
||||
const u32 CMD_TITLE_PX = 14;
|
||||
const u32 CMD_SUB_PX = 10;
|
||||
|
||||
shared static this()
|
||||
{
|
||||
g_NIL_ED = cast(Editor*)&g_nil_ed;
|
||||
}
|
||||
|
||||
95844
test/files/miniaudio.h
Normal file
95844
test/files/miniaudio.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,30 @@
|
||||
import std.stdio;
|
||||
|
||||
struct TestStruct
|
||||
{
|
||||
int value;
|
||||
float value2;
|
||||
double value3;
|
||||
}
|
||||
|
||||
struct TestStruct2
|
||||
{
|
||||
int value;
|
||||
double value2;
|
||||
}
|
||||
|
||||
struct TestStruct3
|
||||
{
|
||||
int value;
|
||||
uint value2;
|
||||
}
|
||||
|
||||
@nogc: bool
|
||||
Test(float flt, int i)
|
||||
{
|
||||
int x = 5;
|
||||
int y = 10;
|
||||
int z = 15;
|
||||
|
||||
x = x + y;
|
||||
x = x - y;
|
||||
@ -67,6 +87,12 @@ int WithParameters(float x, string y)
|
||||
return cast(int)(x) - y[0];
|
||||
}
|
||||
|
||||
struct TestStruct
|
||||
{
|
||||
int value;
|
||||
float value2;
|
||||
}
|
||||
|
||||
T MacroFunc(T)(T x)
|
||||
{
|
||||
return x;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user