Compare commits
8 Commits
fbeb32097e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e6d3cc839 | ||
|
|
1e70444992 | ||
|
|
e40d8773c4 | ||
|
|
46d758c191 | ||
|
|
b5c9e10477 | ||
|
|
8f4c7745f0 | ||
|
|
b2c3cac73d | ||
|
|
cda805574f |
49
build_web.sh
49
build_web.sh
@@ -1,9 +1,46 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
incs="-Isrc/external/SDL/include -Isrc/external/lua/src -Isrc/external/glad -Lsrc/external/SDL/build_web -Isrc"
|
for arg in "$@"; do declare "$arg"='1'; done
|
||||||
wasmflags="-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb -msimd128 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256mb -sUSE_WEBGL2 -sFULL_ES3=1 -sUSE_SDL=3 -sASYNCIFY -sASSERTIONS=2"
|
if [ ! -v release ]; then debug=1; fi
|
||||||
flags="-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths"
|
if [ -v debug ]; then echo "[web debug build]"; fi
|
||||||
dbg="-g -DDEBUG_BUILD=1 -gsource-map"
|
if [ -v release ]; then echo "[web release build]"; fi
|
||||||
rel="-O3 -DDEBUG_BUILD=0"
|
|
||||||
|
|
||||||
emcc -o text_editor.html --shell-file=data/shell.html $flags $incs $wasmflags $dbg -lm -lSDL3 src/text_editor/text_editor.cpp
|
# If emsdk is installed but not sourced in this shell, try the common location.
|
||||||
|
if ! command -v emcc >/dev/null 2>&1; then
|
||||||
|
if [ -f "$HOME/emsdk/emsdk_env.sh" ]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$HOME/emsdk/emsdk_env.sh" >/dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v emcc >/dev/null 2>&1; then
|
||||||
|
echo "error: emcc not found. Source emsdk_env.sh or add emcc to PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build_web
|
||||||
|
|
||||||
|
incs="-Isrc -Isrc/external/glad"
|
||||||
|
flags="-Wall -Wextra -Werror -Wno-error=experimental -Wno-error=unused-parameter -Wformat=2 -Wundef -Wshadow -Wno-missing-field-initializers -Wno-missing-braces -Wno-writable-strings \
|
||||||
|
-fdiagnostics-absolute-paths \
|
||||||
|
-nostdlib++ -fno-exceptions"
|
||||||
|
wasmflags="-sALLOW_MEMORY_GROWTH=0 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256MB \
|
||||||
|
-sUSE_SDL=3 -sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -sFULL_ES3=1 \
|
||||||
|
-sASYNCIFY=1 -sASSERTIONS=2 \
|
||||||
|
-sEXIT_RUNTIME=0 \
|
||||||
|
-msimd128"
|
||||||
|
|
||||||
|
if [ -v debug ]; then
|
||||||
|
flags="$flags -g -gsource-map -DDEBUG_BUILD=1"
|
||||||
|
else
|
||||||
|
flags="$flags -O3 -DDEBUG_BUILD=0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
emcc -o build_web/text_editor.html \
|
||||||
|
--shell-file data/shell.html \
|
||||||
|
$flags $incs $wasmflags \
|
||||||
|
src/text_editor.cpp \
|
||||||
|
-lm
|
||||||
|
|
||||||
|
echo "Wrote build_web/text_editor.html"
|
||||||
|
|||||||
76
data/shell.html
Normal file
76
data/shell.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no">
|
||||||
|
<title>text_editor</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
outline: none;
|
||||||
|
border: 0;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="0"></canvas>
|
||||||
|
<div id="error-box" style="display:none; position:fixed; left:12px; right:12px; bottom:12px; z-index:9999; box-sizing:border-box; max-height:35vh; overflow:auto; padding:10px 12px; border:1px solid #7f1d1d; border-radius:6px; background:rgba(127,29,29,0.94); color:#fff; font:13px/1.35 monospace; white-space:pre-wrap;"></div>
|
||||||
|
<script>
|
||||||
|
const errorBox = document.getElementById('error-box');
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
const text = String(message || 'Unknown error');
|
||||||
|
console.error(text);
|
||||||
|
errorBox.style.display = 'block';
|
||||||
|
errorBox.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('error', (event) => {
|
||||||
|
showError(event.error && event.error.stack ? event.error.stack : event.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('unhandledrejection', (event) => {
|
||||||
|
const reason = event.reason;
|
||||||
|
showError(reason && reason.stack ? reason.stack : reason);
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
canvas: document.getElementById('canvas'),
|
||||||
|
print: (text) => console.log(text),
|
||||||
|
printErr: (text) => showError(text),
|
||||||
|
onAbort: (what) => showError('Aborted: ' + what),
|
||||||
|
setStatus: (text) => { if (text) console.log(text); }
|
||||||
|
};
|
||||||
|
|
||||||
|
function resizeCanvasToDisplaySize() {
|
||||||
|
const canvas = Module.canvas;
|
||||||
|
const dpr = window.devicePixelRatio || 1;
|
||||||
|
const w = Math.max(1, Math.floor(window.innerWidth * dpr));
|
||||||
|
const h = Math.max(1, Math.floor(window.innerHeight * dpr));
|
||||||
|
if (canvas.width !== w || canvas.height !== h) {
|
||||||
|
canvas.width = w;
|
||||||
|
canvas.height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', resizeCanvasToDisplaySize);
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
resizeCanvasToDisplaySize();
|
||||||
|
Module.canvas.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{{ SCRIPT }}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -284,7 +284,7 @@ API void Init(BlockArena *arena) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
API void *PushSize(BlockArena *arena, size_t size) {
|
API void *PushSize(BlockArena *arena, size_t size) {
|
||||||
if (size > (size_t)(arena->end - arena->start)) {
|
if (!arena->blocks || size > (size_t)(arena->end - arena->start)) {
|
||||||
AddBlock(arena, size);
|
AddBlock(arena, size);
|
||||||
}
|
}
|
||||||
U8 *result = arena->start;
|
U8 *result = arena->start;
|
||||||
@@ -323,7 +323,7 @@ API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size)
|
|||||||
BlockArena *arena = (BlockArena *)object;
|
BlockArena *arena = (BlockArena *)object;
|
||||||
if (kind == AllocatorKind_Allocate) {
|
if (kind == AllocatorKind_Allocate) {
|
||||||
return PushSize(arena, size);
|
return PushSize(arena, size);
|
||||||
} else if (AllocatorKind_Deallocate) {
|
} else if (kind == AllocatorKind_Deallocate) {
|
||||||
} else {
|
} else {
|
||||||
Assert(!"invalid codepath");
|
Assert(!"invalid codepath");
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,34 @@ API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if OS_WASM
|
#if OS_WASM
|
||||||
|
BlockArena ScratchArenas[4];
|
||||||
API void InitScratch() {
|
API void InitScratch() {
|
||||||
|
for (int i = 0; i < 4; i += 1) {
|
||||||
|
if (!ScratchArenas[i].blocks) Init(&ScratchArenas[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
API BlockArena *GetScratchEx(BlockArena **conflicts, int conflict_count) {
|
||||||
|
BlockArena *unoccupied = 0;
|
||||||
|
for (int i = 0; i < Lengthof(ScratchArenas); i += 1) {
|
||||||
|
BlockArena *from_pool = &ScratchArenas[i];
|
||||||
|
unoccupied = from_pool;
|
||||||
|
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
|
||||||
|
BlockArena *from_conflict = conflicts[conflict_i];
|
||||||
|
if (from_pool == from_conflict) {
|
||||||
|
unoccupied = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unoccupied) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed to get free scratch memory, this is a fatal error, this shouldnt happen
|
||||||
|
Assert(unoccupied);
|
||||||
|
return unoccupied;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
thread_local VirtualArena ScratchArenas[4];
|
thread_local VirtualArena ScratchArenas[4];
|
||||||
@@ -439,4 +466,148 @@ void RunArenaTest() {
|
|||||||
Release(&arena);
|
Release(&arena);
|
||||||
Assert(MemoryTrackingRecord.len == 0);
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwind-to-null must leave the arena reusable. This catches crashes/UB in
|
||||||
|
// temp-memory style "clear and then allocate again" usage.
|
||||||
|
{
|
||||||
|
BlockArena arena = {};
|
||||||
|
arena.allocator = memory_tracking_allocator;
|
||||||
|
Unwind(&arena, 0);
|
||||||
|
U8 *a = (U8 *)PushSize(&arena, 64);
|
||||||
|
for (int i = 0; i < 64; i += 1) a[i] = (U8)i;
|
||||||
|
Unwind(&arena, 0);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
U8 *b = (U8 *)PushSize(&arena, 128);
|
||||||
|
for (int i = 0; i < 128; i += 1) b[i] = (U8)(255 - i);
|
||||||
|
Release(&arena);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested temp checkpoints, including a child allocation that forces a new
|
||||||
|
// block. Older allocations must survive, newer blocks must be released, and
|
||||||
|
// the checkpoint address must be reused by the next allocation.
|
||||||
|
{
|
||||||
|
BlockArena arena = {};
|
||||||
|
arena.allocator = memory_tracking_allocator;
|
||||||
|
U8 *permanent = (U8 *)PushSize(&arena, 256);
|
||||||
|
for (int i = 0; i < 256; i += 1) permanent[i] = (U8)i;
|
||||||
|
|
||||||
|
U8 *checkpoint_a = arena.start;
|
||||||
|
U8 *temp_a = (U8 *)PushSize(&arena, KiB(64));
|
||||||
|
for (size_t i = 0; i < KiB(64); i += 1) temp_a[i] = 0xA1;
|
||||||
|
|
||||||
|
U8 *checkpoint_b = arena.start;
|
||||||
|
U8 *temp_b = (U8 *)PushSize(&arena, MiB(2));
|
||||||
|
for (size_t i = 0; i < MiB(2); i += 4096) temp_b[i] = 0xB2;
|
||||||
|
Assert(MemoryTrackingRecord.len == 2);
|
||||||
|
|
||||||
|
Unwind(&arena, checkpoint_b);
|
||||||
|
Assert(arena.start == checkpoint_b);
|
||||||
|
Assert(MemoryTrackingRecord.len == 1);
|
||||||
|
for (int i = 0; i < 256; i += 1) Assert(permanent[i] == (U8)i);
|
||||||
|
for (size_t i = 0; i < KiB(64); i += 1) Assert(temp_a[i] == 0xA1);
|
||||||
|
Assert(PushSize(&arena, 32) == checkpoint_b);
|
||||||
|
|
||||||
|
Unwind(&arena, checkpoint_a);
|
||||||
|
Assert(arena.start == checkpoint_a);
|
||||||
|
for (int i = 0; i < 256; i += 1) Assert(permanent[i] == (U8)i);
|
||||||
|
Assert(PushSize(&arena, 32) == checkpoint_a);
|
||||||
|
|
||||||
|
Release(&arena);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeatedly grow through multiple blocks, unwind back through all of them,
|
||||||
|
// allocate again, and do it many times. This is the pattern a temp arena can
|
||||||
|
// hit if one outer checkpoint is reused around variable-size work.
|
||||||
|
{
|
||||||
|
BlockArena arena = {};
|
||||||
|
arena.allocator = memory_tracking_allocator;
|
||||||
|
U8 *guard = (U8 *)PushSize(&arena, 1024);
|
||||||
|
for (int i = 0; i < 1024; i += 1) guard[i] = (U8)i;
|
||||||
|
U8 *base_checkpoint = arena.start;
|
||||||
|
|
||||||
|
for (int cycle = 0; cycle < 32; cycle += 1) {
|
||||||
|
U8 *first_block_temp = (U8 *)PushSize(&arena, KiB(900));
|
||||||
|
first_block_temp[0] = (U8)cycle;
|
||||||
|
first_block_temp[KiB(900) - 1] = (U8)(cycle + 1);
|
||||||
|
U8 *mid_checkpoint = arena.start;
|
||||||
|
|
||||||
|
U8 *large_temp = (U8 *)PushSize(&arena, MiB(2) + (size_t)cycle * 8);
|
||||||
|
large_temp[0] = (U8)(cycle + 2);
|
||||||
|
large_temp[MiB(2) - 1] = (U8)(cycle + 3);
|
||||||
|
U8 *last_temp = (U8 *)PushSize(&arena, KiB(700));
|
||||||
|
last_temp[0] = (U8)(cycle + 4);
|
||||||
|
last_temp[KiB(700) - 1] = (U8)(cycle + 5);
|
||||||
|
Assert(MemoryTrackingRecord.len == 3);
|
||||||
|
|
||||||
|
Unwind(&arena, mid_checkpoint);
|
||||||
|
Assert(arena.start == mid_checkpoint);
|
||||||
|
Assert(MemoryTrackingRecord.len == 1);
|
||||||
|
Assert(first_block_temp[0] == (U8)cycle);
|
||||||
|
Assert(first_block_temp[KiB(900) - 1] == (U8)(cycle + 1));
|
||||||
|
for (int i = 0; i < 1024; i += 1) Assert(guard[i] == (U8)i);
|
||||||
|
Assert(PushSize(&arena, 16) == mid_checkpoint);
|
||||||
|
|
||||||
|
Unwind(&arena, base_checkpoint);
|
||||||
|
Assert(arena.start == base_checkpoint);
|
||||||
|
Assert(MemoryTrackingRecord.len == 1);
|
||||||
|
for (int i = 0; i < 1024; i += 1) Assert(guard[i] == (U8)i);
|
||||||
|
Assert(PushSize(&arena, 16) == base_checkpoint);
|
||||||
|
Unwind(&arena, base_checkpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Release(&arena);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkpoint exactly at the end of a block is legal; unwinding to it should
|
||||||
|
// drop later blocks and leave the full block as the current block.
|
||||||
|
{
|
||||||
|
BlockArena arena = {};
|
||||||
|
arena.allocator = memory_tracking_allocator;
|
||||||
|
PushSize(&arena, 1);
|
||||||
|
size_t remaining = (size_t)(arena.end - arena.start);
|
||||||
|
PushSize(&arena, remaining);
|
||||||
|
U8 *checkpoint = arena.start;
|
||||||
|
Assert(checkpoint == arena.end);
|
||||||
|
PushSize(&arena, 1);
|
||||||
|
Assert(MemoryTrackingRecord.len == 2);
|
||||||
|
Unwind(&arena, checkpoint);
|
||||||
|
Assert(arena.blocks);
|
||||||
|
Assert(arena.blocks->next == NULL);
|
||||||
|
Assert(arena.start == checkpoint);
|
||||||
|
Assert(arena.end == checkpoint);
|
||||||
|
PushSize(&arena, 1);
|
||||||
|
Assert(MemoryTrackingRecord.len == 2);
|
||||||
|
Release(&arena);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic stack-style stress test: allocate temps at many nested
|
||||||
|
// checkpoints, unwind in reverse order, and verify surviving bytes.
|
||||||
|
{
|
||||||
|
BlockArena arena = {};
|
||||||
|
arena.allocator = memory_tracking_allocator;
|
||||||
|
U8 *checkpoints[128];
|
||||||
|
U8 *ptrs[128];
|
||||||
|
size_t sizes[128];
|
||||||
|
for (int i = 0; i < 128; i += 1) {
|
||||||
|
checkpoints[i] = arena.start;
|
||||||
|
sizes[i] = (size_t)(((i * 7919) % (64 * 1024)) + 1);
|
||||||
|
ptrs[i] = (U8 *)PushSize(&arena, sizes[i]);
|
||||||
|
for (size_t j = 0; j < sizes[i]; j += 4096) ptrs[i][j] = (U8)i;
|
||||||
|
ptrs[i][sizes[i] - 1] = (U8)i;
|
||||||
|
}
|
||||||
|
for (int i = 127; i >= 0; i -= 1) {
|
||||||
|
Assert(ptrs[i][0] == (U8)i);
|
||||||
|
Assert(ptrs[i][sizes[i] - 1] == (U8)i);
|
||||||
|
Unwind(&arena, checkpoints[i]);
|
||||||
|
Assert(arena.start == checkpoints[i]);
|
||||||
|
}
|
||||||
|
Unwind(&arena, 0);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
Release(&arena);
|
||||||
|
Assert(MemoryTrackingRecord.len == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ struct BlockArena {
|
|||||||
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
|
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
API void Init(BlockArena *arena);
|
||||||
API void *PushSize(BlockArena *arena, size_t size);
|
API void *PushSize(BlockArena *arena, size_t size);
|
||||||
API void Release(BlockArena *arena);
|
API void Release(BlockArena *arena);
|
||||||
API void Unwind(BlockArena *arena, U8 *pos);
|
API void Unwind(BlockArena *arena, U8 *pos);
|
||||||
@@ -98,16 +99,43 @@ API void Release(VirtualArena *arena);
|
|||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
// Scratch
|
// Scratch
|
||||||
#if OS_WASM
|
#if OS_WASM
|
||||||
|
extern BlockArena ScratchArenas[4];
|
||||||
|
API BlockArena *GetScratchEx(BlockArena **conflicts, int conflict_count);
|
||||||
struct Scratch {
|
struct Scratch {
|
||||||
BlockArena arena = {};
|
BlockArena *arena;
|
||||||
Scratch() {}
|
U8 *p;
|
||||||
Scratch(BlockArena *conflict) {}
|
Scratch() {arena = &ScratchArenas[0]; if (!arena->blocks) Init(arena); p = arena->start; arena->refs += 1;}
|
||||||
Scratch(BlockArena *c1, BlockArena *c2) {}
|
Scratch(BlockArena *conflict) {
|
||||||
Scratch(Allocator conflict) {}
|
BlockArena *conf[] = {conflict};
|
||||||
Scratch(Allocator c1, Allocator c2) {}
|
arena = GetScratchEx(conf, Lengthof(conf));
|
||||||
~Scratch() { Release(&arena); }
|
if (!arena->blocks) Init(arena);
|
||||||
operator BlockArena *() { return &arena; }
|
p = arena->start;
|
||||||
operator Allocator() { return arena; }
|
arena->refs += 1;
|
||||||
|
}
|
||||||
|
Scratch(BlockArena *c1, BlockArena *c2) {
|
||||||
|
BlockArena *conf[] = {c1, c2};
|
||||||
|
arena = GetScratchEx(conf, Lengthof(conf));
|
||||||
|
if (!arena->blocks) Init(arena);
|
||||||
|
p = arena->start;
|
||||||
|
arena->refs += 1;
|
||||||
|
}
|
||||||
|
Scratch(Allocator conflict) {
|
||||||
|
BlockArena *conf[] = {(BlockArena *)conflict.object};
|
||||||
|
arena = GetScratchEx(conf, Lengthof(conf));
|
||||||
|
if (!arena->blocks) Init(arena);
|
||||||
|
p = arena->start;
|
||||||
|
arena->refs += 1;
|
||||||
|
}
|
||||||
|
Scratch(Allocator c1, Allocator c2) {
|
||||||
|
BlockArena *conf[] = {(BlockArena *)c1.object, (BlockArena *)c2.object};
|
||||||
|
arena = GetScratchEx(conf, Lengthof(conf));
|
||||||
|
if (!arena->blocks) Init(arena);
|
||||||
|
p = arena->start;
|
||||||
|
arena->refs += 1;
|
||||||
|
}
|
||||||
|
~Scratch() { Unwind(arena, p); arena->refs -= 1; }
|
||||||
|
operator BlockArena *() { return arena; }
|
||||||
|
operator Allocator() { return *arena; }
|
||||||
private: // @Note: Disable copy constructors, cause its error prone
|
private: // @Note: Disable copy constructors, cause its error prone
|
||||||
Scratch(Scratch &arena);
|
Scratch(Scratch &arena);
|
||||||
Scratch(Scratch &arena, Scratch &a2);
|
Scratch(Scratch &arena, Scratch &a2);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ RegisterVariable(Int, WaitForEvents, 1);
|
|||||||
RegisterVariable(Int, DrawLineNumbers, 1);
|
RegisterVariable(Int, DrawLineNumbers, 1);
|
||||||
RegisterVariable(Int, DrawScrollbar, 1);
|
RegisterVariable(Int, DrawScrollbar, 1);
|
||||||
RegisterVariable(Int, IndentSize, 4);
|
RegisterVariable(Int, IndentSize, 4);
|
||||||
RegisterVariable(Int, FontSize, 15);
|
RegisterVariable(Int, FontSize, 20);
|
||||||
RegisterVariable(String, PathToFont, "");
|
RegisterVariable(String, PathToFont, "");
|
||||||
RegisterVariable(Float, UndoMergeTime, 0.3);
|
RegisterVariable(Float, UndoMergeTime, 0.3);
|
||||||
RegisterVariable(Float, JumpHistoryMergeTime, 0.3);
|
RegisterVariable(Float, JumpHistoryMergeTime, 0.3);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_BASIC_COMMANDS
|
||||||
void CMD_Redo() {
|
void CMD_Redo() {
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
BSet active = GetBSet(ActiveWindowID);
|
||||||
RedoEdit(active.buffer, &active.view->carets);
|
RedoEdit(active.buffer, &active.view->carets);
|
||||||
@@ -271,3 +272,4 @@ void CMD_PlayMacro() {
|
|||||||
|
|
||||||
For (MacroPlayback) Add(&EventPlayback, it);
|
For (MacroPlayback) Add(&EventPlayback, it);
|
||||||
} RegisterCommand(CMD_PlayMacro, "alt-m", "Start playing back a macro recording");
|
} RegisterCommand(CMD_PlayMacro, "alt-m", "Start playing back a macro recording");
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_BUILD_WINDOW
|
||||||
WindowID BuildWindowID;
|
WindowID BuildWindowID;
|
||||||
ViewID BuildViewID;
|
ViewID BuildViewID;
|
||||||
BufferID BuildBufferID;
|
BufferID BuildBufferID;
|
||||||
@@ -90,3 +91,4 @@ void CMD_ShowBuildWindow() {
|
|||||||
main.window->visible = false;
|
main.window->visible = false;
|
||||||
}
|
}
|
||||||
} RegisterCommand(CMD_ShowBuildWindow, "ctrl-grave", "Toggles visibility of the build window");
|
} RegisterCommand(CMD_ShowBuildWindow, "ctrl-grave", "Toggles visibility of the build window");
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_COMMAND_RUNNER_WINDOW
|
||||||
WindowID CommandRunnerWindowID;
|
WindowID CommandRunnerWindowID;
|
||||||
|
|
||||||
void CMD_ShowCommandRunner() {
|
void CMD_ShowCommandRunner() {
|
||||||
@@ -65,3 +66,4 @@ void InitCommandRunnerWindow() {
|
|||||||
window->jump_history = false;
|
window->jump_history = false;
|
||||||
AddCommand(&view->commands, "Open", OpenKeySet, CMD_OpenForRunnerWindow);
|
AddCommand(&view->commands, "Open", OpenKeySet, CMD_OpenForRunnerWindow);
|
||||||
}
|
}
|
||||||
|
#endif // PLUGIN_COMMAND_RUNNER_WINDOW
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_COMMAND_WINDOW
|
||||||
WindowID CommandWindowID;
|
WindowID CommandWindowID;
|
||||||
|
|
||||||
void CMD_ShowCommands() {
|
void CMD_ShowCommands() {
|
||||||
@@ -84,3 +85,4 @@ void InitCommandWindow() {
|
|||||||
window->lose_focus_on_escape = true;
|
window->lose_focus_on_escape = true;
|
||||||
window->jump_history = false;
|
window->jump_history = false;
|
||||||
}
|
}
|
||||||
|
#endif // PLUGIN_COMMAND_WINDOW
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_DEBUG_WINDOW
|
||||||
WindowID DebugWindowID;
|
WindowID DebugWindowID;
|
||||||
ViewID DebugViewID;
|
ViewID DebugViewID;
|
||||||
BufferID DebugBufferID;
|
BufferID DebugBufferID;
|
||||||
@@ -65,3 +66,4 @@ void CMD_ToggleDebug() {
|
|||||||
Window *window = GetWindow(DebugWindowID);
|
Window *window = GetWindow(DebugWindowID);
|
||||||
window->visible = !window->visible;
|
window->visible = !window->visible;
|
||||||
} RegisterCommand(CMD_ToggleDebug, "ctrl-0", "Open a floating window that might become useful for debugging");
|
} RegisterCommand(CMD_ToggleDebug, "ctrl-0", "Open a floating window that might become useful for debugging");
|
||||||
|
#endif // PLUGIN_DEBUG_WINDOW
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_DIRECTORY_NAVIGATION
|
||||||
// @todo: On save rename files, delete files it should apply the changes
|
// @todo: On save rename files, delete files it should apply the changes
|
||||||
// Instead of toying with Reopen maybe it should actually detect changes in directory etc. on update
|
// Instead of toying with Reopen maybe it should actually detect changes in directory etc. on update
|
||||||
|
|
||||||
@@ -204,3 +205,4 @@ void DestroyDirectoryWatcher(DirectoryWatcher *w)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_PROJECT_MANAGEMENT
|
||||||
void SetProjectFolder(String dir) {
|
void SetProjectFolder(String dir) {
|
||||||
ProjectFolder = Intern(&GlobalInternTable, dir);
|
ProjectFolder = Intern(&GlobalInternTable, dir);
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
@@ -135,3 +136,4 @@ void CO_CreateProject(mco_coro *co) {
|
|||||||
|
|
||||||
CO_OpenCode(co);
|
CO_OpenCode(co);
|
||||||
} RegisterCoroutineCommand(CO_CreateProject, "", "Creates a project in current buffer directory with template files and all that, asks user for input etc.");
|
} RegisterCoroutineCommand(CO_CreateProject, "", "Creates a project in current buffer directory with template files and all that, asks user for input etc.");
|
||||||
|
#endif
|
||||||
@@ -1 +1,3 @@
|
|||||||
|
#if PLUGIN_PROJECT_MANAGEMENT
|
||||||
void SetProjectFolder(String name);
|
void SetProjectFolder(String name);
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_RECORD_EVENTS
|
||||||
Buffer *EventBuffer;
|
Buffer *EventBuffer;
|
||||||
|
|
||||||
void Serialize(Buffer *buffer, String name, EventKind *kind) {
|
void Serialize(Buffer *buffer, String name, EventKind *kind) {
|
||||||
@@ -68,3 +69,4 @@ void Serialize(Buffer *buffer, Event *e) {
|
|||||||
void CMD_CopyEvents() {
|
void CMD_CopyEvents() {
|
||||||
SaveStringInClipboard(GetString(EventBuffer));
|
SaveStringInClipboard(GetString(EventBuffer));
|
||||||
} RegisterCommand(CMD_CopyEvents, "ctrl-shift-alt-j", "Copy all the events from the EventBuffer");
|
} RegisterCommand(CMD_CopyEvents, "ctrl-shift-alt-j", "Copy all the events from the EventBuffer");
|
||||||
|
#endif
|
||||||
@@ -1 +1,3 @@
|
|||||||
|
#if PLUGIN_RECORD_GC
|
||||||
Buffer *GCInfoBuffer;
|
Buffer *GCInfoBuffer;
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_SEARCH_OPEN_BUFFERS
|
||||||
struct SearchOpenBuffersParams {
|
struct SearchOpenBuffersParams {
|
||||||
String16 needle;
|
String16 needle;
|
||||||
BufferID buffer;
|
BufferID buffer;
|
||||||
@@ -127,3 +128,4 @@ void CMD_SearchOpenBuffers() {
|
|||||||
}
|
}
|
||||||
SelectRange(main.view, GetLineRangeWithoutNL(main.buffer, 0));
|
SelectRange(main.view, GetLineRangeWithoutNL(main.buffer, 0));
|
||||||
} RegisterCommand(CMD_SearchOpenBuffers, "ctrl-shift-f", "Interactive search over the entire project in a new buffer view");
|
} RegisterCommand(CMD_SearchOpenBuffers, "ctrl-shift-f", "Interactive search over the entire project in a new buffer view");
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_SEARCH_WINDOW
|
||||||
Int SearchBufferChangeID;
|
Int SearchBufferChangeID;
|
||||||
|
|
||||||
void CMD_Search() {
|
void CMD_Search() {
|
||||||
@@ -110,3 +111,4 @@ void UpdateSearchWindow() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_STATUS_WINDOW
|
||||||
WindowID StatusWindowID;
|
WindowID StatusWindowID;
|
||||||
|
|
||||||
void InitStatusWindow() {
|
void InitStatusWindow() {
|
||||||
@@ -97,3 +98,4 @@ void UpdateStatusWindow() {
|
|||||||
SelectRange(title.view, MakeRange(0));
|
SelectRange(title.view, MakeRange(0));
|
||||||
ResetHistory(title.buffer);
|
ResetHistory(title.buffer);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#if PLUGIN_TESTS
|
#if PLUGIN_TESTS
|
||||||
|
|
||||||
|
|
||||||
void Wait(mco_coro *co) {
|
void Wait(mco_coro *co) {
|
||||||
{Event ev = {};ev.kind = EVENT_KIND_INVALID; Add(&EventPlayback, ev);}
|
{Event ev = {};ev.kind = EVENT_KIND_INVALID; Add(&EventPlayback, ev);}
|
||||||
Event *event = NULL;
|
Event *event = NULL;
|
||||||
@@ -120,4 +119,4 @@ Memes and stuff)FOO";
|
|||||||
} RegisterCoroutineCommand(CO_RunTests, "", "Basic tests");
|
} RegisterCoroutineCommand(CO_RunTests, "", "Basic tests");
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif // PLUGIN_TESTS
|
||||||
|
|||||||
118
src/plugin_tutorial.cpp
Normal file
118
src/plugin_tutorial.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#if PLUGIN_TUTORIAL
|
||||||
|
|
||||||
|
#define RegisterTutorialSection(NAME, DESC, STRING)\
|
||||||
|
String NAME##_string = STRING;\
|
||||||
|
void CMD_##NAME() {\
|
||||||
|
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(ProjectFolder, #NAME), NAME##_string.len * 4 + 4096);\
|
||||||
|
buffer->temp = true;\
|
||||||
|
RawAppend(buffer, NAME##_string);\
|
||||||
|
buffer->dirty = false;\
|
||||||
|
Open(buffer->name);\
|
||||||
|
} RegisterCommand(CMD_##NAME, "", DESC);
|
||||||
|
|
||||||
|
RegisterTutorialSection(EnterTheTutorial, "The guide to sailing the text", R"==(
|
||||||
|
|
||||||
|
Hello sailor!
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
I see you have entered the unknown
|
||||||
|
text waters of the internet.
|
||||||
|
|
||||||
|
Before we set sail, right click:
|
||||||
|
|
||||||
|
:CoolText
|
||||||
|
|
||||||
|
...and watch the waters stir.
|
||||||
|
|
||||||
|
)==");
|
||||||
|
|
||||||
|
RegisterTutorialSection(CoolText, "Coolest text inside the coolest tutorial", R"==(
|
||||||
|
|
||||||
|
The text can lead you
|
||||||
|
into interesting places
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Do not be afraid. Try these too:
|
||||||
|
|
||||||
|
:MakeFontLarger
|
||||||
|
:MakeFontSmaller
|
||||||
|
|
||||||
|
Make the letters huge.
|
||||||
|
Then make them tiny again.
|
||||||
|
and then ...
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
:GoToNextSectionOfTheTutorial!
|
||||||
|
|
||||||
|
)==");
|
||||||
|
|
||||||
|
RegisterTutorialSection(GoToNextSectionOfTheTutorial, "Yes!", R"==(
|
||||||
|
Special words listen to keys too:
|
||||||
|
|
||||||
|
Ctrl-+ Ctrl--
|
||||||
|
|
||||||
|
Even right click has a twin:
|
||||||
|
|
||||||
|
Ctrl-Q F12
|
||||||
|
|
||||||
|
Put your caret here and try:
|
||||||
|
|
||||||
|
:Prev
|
||||||
|
:New (beware, you may never return! Hint: Take a look at the bar on the bottom)
|
||||||
|
:HowToFindCommands
|
||||||
|
)==");
|
||||||
|
|
||||||
|
RegisterTutorialSection(HowToFindCommands, "Tutorial on finding the commands", R"==(
|
||||||
|
Open the map:
|
||||||
|
|
||||||
|
:ShowCommands (Ctrl-Shift-P)
|
||||||
|
|
||||||
|
Type a few letters.
|
||||||
|
Press (Enter) to choose.
|
||||||
|
|
||||||
|
These special words are not magical
|
||||||
|
You can easily find them
|
||||||
|
and use.
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
HowToBindCommandsToKeys
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
)==");
|
||||||
|
|
||||||
|
RegisterTutorialSection(HowToBindCommandsToKeys, "how to bind commands to keys", R"==(
|
||||||
|
|
||||||
|
We will start easy. Try selecting the entire line below and (ctrl-q / right click / F12)
|
||||||
|
|
||||||
|
:Set DrawLineNumbers 0
|
||||||
|
:Set TextColor ffaa0000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Make it normal again:
|
||||||
|
|
||||||
|
:Set DrawLineNumbers 1
|
||||||
|
:Set TextColor ff21201d
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
And of course this setup also works for keys:
|
||||||
|
|
||||||
|
:Set MakeFontLarger 'ctrl-t'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
See the map for this:
|
||||||
|
|
||||||
|
:OpenConfigOptions
|
||||||
|
|
||||||
|
)==");
|
||||||
|
|
||||||
|
void InitTutorial() {
|
||||||
|
CMD_EnterTheTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#if PLUGIN_WINDOW_MANAGEMENT
|
||||||
void CMD_JumpPrev() {
|
void CMD_JumpPrev() {
|
||||||
BSet main = GetBSet(PrimaryWindowID);
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
JumpToLastValidView(main.window);
|
JumpToLastValidView(main.window);
|
||||||
@@ -80,3 +81,4 @@ void CMD_GotoPrevInList() {
|
|||||||
BSet main = GetBSet(PrimaryWindowID);
|
BSet main = GetBSet(PrimaryWindowID);
|
||||||
GotoNextInList(main.window, -1);
|
GotoNextInList(main.window, -1);
|
||||||
} RegisterCommand(CMD_GotoPrevInList, "alt-e | shift-f8", "For example: when jumping from build panel to build error, a jump point is setup, user can click this button to go over to the previous compiler error");
|
} RegisterCommand(CMD_GotoPrevInList, "alt-e | shift-f8", "For example: when jumping from build panel to build error, a jump point is setup, user can click this button to go over to the previous compiler error");
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -164,16 +164,34 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
|
|||||||
#define STBSP__ASAN
|
#define STBSP__ASAN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if defined(__has_attribute)
|
||||||
|
#if __has_attribute(__no_sanitize__)
|
||||||
|
// stb_sprintf intentionally uses unaligned word loads/stores for speed.
|
||||||
|
// UBSan reports these on x86/x64 even though the hardware permits them.
|
||||||
|
#define STBSP__UBSAN __attribute__((__no_sanitize__("undefined")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ >= 5)
|
||||||
|
#define STBSP__UBSAN __attribute__((__no_sanitize_undefined__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBSP__UBSAN
|
||||||
|
#define STBSP__UBSAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STBSP__SANITIZE_OFF STBSP__ASAN STBSP__UBSAN
|
||||||
|
|
||||||
#ifdef STB_SPRINTF_STATIC
|
#ifdef STB_SPRINTF_STATIC
|
||||||
#define STBSP__PUBLICDEC static
|
#define STBSP__PUBLICDEC static
|
||||||
#define STBSP__PUBLICDEF static STBSP__ASAN
|
#define STBSP__PUBLICDEF static STBSP__SANITIZE_OFF
|
||||||
#else
|
#else
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define STBSP__PUBLICDEC extern "C"
|
#define STBSP__PUBLICDEC extern "C"
|
||||||
#define STBSP__PUBLICDEF extern "C" STBSP__ASAN
|
#define STBSP__PUBLICDEF extern "C" STBSP__SANITIZE_OFF
|
||||||
#else
|
#else
|
||||||
#define STBSP__PUBLICDEC extern
|
#define STBSP__PUBLICDEC extern
|
||||||
#define STBSP__PUBLICDEF STBSP__ASAN
|
#define STBSP__PUBLICDEF STBSP__SANITIZE_OFF
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -73,8 +73,7 @@
|
|||||||
#include "render_opengl.cpp"
|
#include "render_opengl.cpp"
|
||||||
|
|
||||||
#define PLUGIN_CONFIG 1
|
#define PLUGIN_CONFIG 1
|
||||||
#define PLUGIN_SEARCH_WINDOW 1
|
#define PLUGIN_TUTORIAL 1
|
||||||
#define PLUGIN_PROJECT_MANAGEMENT 1
|
|
||||||
#define PLUGIN_WINDOW_MANAGEMENT 1
|
#define PLUGIN_WINDOW_MANAGEMENT 1
|
||||||
#define PLUGIN_DIRECTORY_NAVIGATION 1
|
#define PLUGIN_DIRECTORY_NAVIGATION 1
|
||||||
#define PLUGIN_SEARCH_OPEN_BUFFERS 1
|
#define PLUGIN_SEARCH_OPEN_BUFFERS 1
|
||||||
@@ -88,7 +87,6 @@
|
|||||||
#define PLUGIN_DEBUG_WINDOW 1
|
#define PLUGIN_DEBUG_WINDOW 1
|
||||||
#define PLUGIN_RECORD_GC 1
|
#define PLUGIN_RECORD_GC 1
|
||||||
#define PLUGIN_RECORD_EVENTS 1
|
#define PLUGIN_RECORD_EVENTS 1
|
||||||
#define PLUGIN_DIRECTORY_NAVIGATION 1
|
|
||||||
#define PLUGIN_LOAD_VCVARS OS_WINDOWS
|
#define PLUGIN_LOAD_VCVARS OS_WINDOWS
|
||||||
#define PLUGIN_REMEDYBG OS_WINDOWS
|
#define PLUGIN_REMEDYBG OS_WINDOWS
|
||||||
#define PLUGIN_FILE_COMMANDS 1
|
#define PLUGIN_FILE_COMMANDS 1
|
||||||
@@ -135,6 +133,7 @@
|
|||||||
#include "plugin_file_commands.cpp"
|
#include "plugin_file_commands.cpp"
|
||||||
#include "plugin_word_complete.cpp"
|
#include "plugin_word_complete.cpp"
|
||||||
#include "plugin_tests.cpp"
|
#include "plugin_tests.cpp"
|
||||||
|
#include "plugin_tutorial.cpp"
|
||||||
|
|
||||||
#if OS_WASM
|
#if OS_WASM
|
||||||
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
|
EM_JS(void, JS_SetMouseCursor, (const char *cursor_str), {
|
||||||
@@ -987,6 +986,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if PLUGIN_TESTS
|
||||||
if (1) {
|
if (1) {
|
||||||
RunArenaTest();
|
RunArenaTest();
|
||||||
For (TestFunctions) {
|
For (TestFunctions) {
|
||||||
@@ -996,6 +996,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
// ReportErrorf("Testing DONE\n");
|
// ReportErrorf("Testing DONE\n");
|
||||||
// return 0;
|
// return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
ReportErrorf("Couldn't initialize SDL! %s", SDL_GetError());
|
ReportErrorf("Couldn't initialize SDL! %s", SDL_GetError());
|
||||||
@@ -1028,6 +1029,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
int hhalf = 1000;
|
int hhalf = 1000;
|
||||||
int xhalf = 100;
|
int xhalf = 100;
|
||||||
int yhalf = 100;
|
int yhalf = 100;
|
||||||
|
Unused(xhalf); Unused(yhalf);
|
||||||
#else
|
#else
|
||||||
SDL_DisplayID primary_display_id = SDL_GetPrimaryDisplay();
|
SDL_DisplayID primary_display_id = SDL_GetPrimaryDisplay();
|
||||||
const SDL_DisplayMode *display_mode = SDL_GetCurrentDisplayMode(primary_display_id);
|
const SDL_DisplayMode *display_mode = SDL_GetCurrentDisplayMode(primary_display_id);
|
||||||
@@ -1043,7 +1045,9 @@ int main(int argc, char **argv, char **envp)
|
|||||||
ReportErrorf("Couldn't create window! %s", SDL_GetError());
|
ReportErrorf("Couldn't create window! %s", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#if !OS_LINUX
|
||||||
SDL_SetWindowPosition(SDLWindow, xhalf, yhalf);
|
SDL_SetWindowPosition(SDLWindow, xhalf, yhalf);
|
||||||
|
#endif
|
||||||
|
|
||||||
SDL_WindowGLContext = SDL_GL_CreateContext(SDLWindow);
|
SDL_WindowGLContext = SDL_GL_CreateContext(SDLWindow);
|
||||||
SDL_GL_MakeCurrent(SDLWindow, SDL_WindowGLContext);
|
SDL_GL_MakeCurrent(SDLWindow, SDL_WindowGLContext);
|
||||||
@@ -1065,10 +1069,12 @@ int main(int argc, char **argv, char **envp)
|
|||||||
SDL_StartTextInput(SDLWindow);
|
SDL_StartTextInput(SDLWindow);
|
||||||
SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, true);
|
SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, true);
|
||||||
SDL_GL_SetSwapInterval(1); // vsync
|
SDL_GL_SetSwapInterval(1); // vsync
|
||||||
|
|
||||||
{
|
{
|
||||||
float scale = SDL_GetWindowDisplayScale(SDLWindow);
|
float scale = SDL_GetWindowDisplayScale(SDLWindow);
|
||||||
if (scale != 1.0f) DPIScale = scale;
|
if (scale != 1.0f) DPIScale = scale;
|
||||||
}
|
}
|
||||||
|
SDL_SyncWindow(SDLWindow);
|
||||||
|
|
||||||
// InitBuffers
|
// InitBuffers
|
||||||
{
|
{
|
||||||
@@ -1137,6 +1143,12 @@ int main(int argc, char **argv, char **envp)
|
|||||||
Open(argv[i]);
|
Open(argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PLUGIN_TUTORIAL
|
||||||
|
if (argc == 1) {
|
||||||
|
InitTutorial();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if PLUGIN_LOAD_VCVARS
|
#if PLUGIN_LOAD_VCVARS
|
||||||
LoadVCVars();
|
LoadVCVars();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ void IndentedNewLine(View *view) {
|
|||||||
For(view->carets) {
|
For(view->carets) {
|
||||||
Int front = GetFront(it);
|
Int front = GetFront(it);
|
||||||
Int indent = GetLineIndent(buffer, PosToLine(buffer, front));
|
Int indent = GetLineIndent(buffer, PosToLine(buffer, front));
|
||||||
String string = Format(scratch, "\n%.*s", indent, " ");
|
String string = Format(scratch, "\n%.*s", (int)indent, " ");
|
||||||
String16 string16 = ToString16(scratch, string);
|
String16 string16 = ToString16(scratch, string);
|
||||||
AddEdit(&edits, it.range, string16);
|
AddEdit(&edits, it.range, string16);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user