more movement options

This commit is contained in:
Matthew 2025-10-04 16:33:14 +10:00
parent 9720e22f6a
commit 70f51642cd

View File

@ -3,6 +3,7 @@ import core.stdc.stdio : EOF;
import parsing; import parsing;
import std.format : sformat; import std.format : sformat;
import std.math.algebraic : abs; import std.math.algebraic : abs;
import editor;
struct FlatBuffer struct FlatBuffer
{ {
@ -48,6 +49,41 @@ enum WalkDir
Forward = +1, Forward = +1,
} }
const bool[128] SYM_TOKENS = [
'`': true,
'"': true,
'\'': true,
'[': true,
']': true,
'~': true,
'!': true,
'@': true,
'#': true,
'$': true,
'%': true,
'^': true,
'&': true,
'*': true,
'(': true,
')': true,
'-': true,
'_': true,
'=': true,
'+': true,
'|': true,
'}': true,
'{': true,
',': true,
'.': true,
'?': true,
'>': true,
'<': true,
':': true,
'/': true,
'\\': true,
';': true,
];
FlatBuffer FlatBuffer
CreateFlatBuffer(u8[] data) CreateFlatBuffer(u8[] data)
{ {
@ -94,10 +130,7 @@ CountLF(u8[] data)
u64 lf_count = 0; u64 lf_count = 0;
for(u64 i = 0; i < data.length; i += 1) for(u64 i = 0; i < data.length; i += 1)
{ {
if(data.ptr[i] == '\n') lf_count += u64(data.ptr[i] == '\n');
{
lf_count += 1;
}
} }
return lf_count; return lf_count;
@ -183,11 +216,7 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos)
for(u64 i = 0; i < length; i += 1) for(u64 i = 0; i < length; i += 1)
{ {
fb.buf_pos += 1; fb.buf_pos += 1;
fb.lf_count += u64(insert.ptr[i] == '\n');
if(insert.ptr[i] == '\n')
{
fb.lf_count += 1;
}
} }
if(length == 1) if(length == 1)
@ -507,19 +536,167 @@ MoveToEmptyLine(bool up)(FlatBuffer* fb)
} }
} }
pragma(inline) bool
IsLetter(u8 ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
pragma(inline) bool
IsNumber(u8 ch)
{
return ch >= '0' && ch <= '9';
}
pragma(inline) bool
IsSymbol(u8 ch)
{
return ch < 128 && SYM_TOKENS[ch];
}
enum ChType
{
Letter,
Number,
Symbol,
Whitespace,
}
bool
CheckChMatch(u8 ch, ChType start_type)
{
return (start_type == ChType.Letter && !IsLetter(ch)) ||
(start_type == ChType.Number && (!IsNumber(ch) && ch != '.')) ||
(start_type == ChType.Symbol && !IsSymbol(ch));
}
ChType
GetChType(u8 ch)
{
ChType type = ChType.Letter;
if(IsNumber(ch))
{
type = ChType.Number;
}
else if(IsSymbol(ch))
{
type = ChType.Symbol;
}
else if(CheckWhiteSpace(ch))
{
type = ChType.Whitespace;
}
return type;
}
void
MoveToWordEdge(bool forward)(FlatBuffer* fb)
{
u64 step = forward ? 1 : -1;
if((forward && fb.buf_pos < fb.length-1) || (!forward && fb.buf_pos > 0))
{
ChType type = GetChType(fb.data[fb.buf_pos]);
if(type != GetChType(fb.data[fb.buf_pos+step]))
{
fb.buf_pos += step;
}
else for(u64 i = fb.buf_pos+step; true; i += step)
{
static if(forward)
{
u8 next = i < fb.length-1 ? fb.data[i+1] : 0;
}
else
{
u8 next = i > 1 ? fb.data[i-1] : 0;
}
static if(forward) if(i == fb.length-2)
{
fb.buf_pos = i;
fb.buf_pos += u64(GetChType(next) == type);
break;
}
static if(!forward) if(i == 1)
{
fb.buf_pos = i;
fb.buf_pos += GetChType(next) == type ? -1 : 0;
break;
}
if(CheckChMatch(next, type))
{
fb.buf_pos = i;
break;
}
}
while(CheckWhiteSpace(fb.data[fb.buf_pos]))
{
bool exit = forward ? fb.buf_pos == fb.length-1 : fb.buf_pos == 0;
if(exit) break;
fb.buf_pos += step;
}
}
}
void
MoveToNextWord(bool forward)(FlatBuffer* fb)
{
ChType type = GetChType(fb.data[fb.buf_pos]);
bool hit_ws;
u64 step = forward ? 1 : -1;
for(u64 i = fb.buf_pos; true; i += step) with(ChType)
{
static if(forward) if(i == fb.length-1)
{
fb.buf_pos = i;
break;
}
static if(!forward) if(i == 0)
{
fb.buf_pos = i;
break;
}
u8 ch = fb.data[i];
if(CheckWhiteSpace(ch))
{
hit_ws = true;
continue;
}
if(hit_ws)
{
fb.buf_pos = i;
break;
}
if(CheckChMatch(ch, type))
{
fb.buf_pos = i;
break;
}
}
assert(fb.buf_pos >= 0 && fb.buf_pos <= fb.length);
}
bool bool
Move(FlatBuffer* fb, Input key, Modifier md) Move(FlatBuffer* fb, Input key, Modifier md)
{ {
bool taken; bool taken;
switch(key) with(Input) if(md & (MD.LeftShift | MD.RightShift))
{
case Home: MoveToSOL(fb); taken = true; break;
case End: MoveToEOL(fb); taken = true; break;
default: break;
}
if(!taken && md & (MD.LeftShift | MD.RightShift))
{ {
switch(key) with(Input) switch(key) with(Input)
{ {
@ -533,16 +710,24 @@ Move(FlatBuffer* fb, Input key, Modifier md)
} break; } break;
case Left: case Left:
{ {
if(fb.buf_pos > 0)
{
MoveToWordEdge!(false)(fb);
}
} break; } break;
case Right: case Right:
{ {
if(fb.buf_pos < fb.length)
{
MoveToWordEdge!(true)(fb);
}
} break; } break;
case Home: fb.buf_pos = 0; taken = true; break;
case End: fb.buf_pos = fb.length; taken = true; break;
default: break; default: break;
} }
} }
else if(!taken && md & (MD.LeftCtrl | MD.RightCtrl)) else if(md & (MD.LeftCtrl | MD.RightCtrl))
{ {
switch(key) with(Input) switch(key) with(Input)
{ {
@ -551,20 +736,25 @@ Move(FlatBuffer* fb, Input key, Modifier md)
} break; } break;
case Down: case Down:
{ {
} break; } break;
case Left: case Left:
{ {
if(fb.buf_pos > 0)
{
MoveToNextWord!(false)(fb);
}
} break; } break;
case Right: case Right:
{ {
if(fb.buf_pos < fb.length)
{
MoveToNextWord!(true)(fb);
}
} break; } break;
default: break; default: break;
} }
} }
else if(!taken) else
{ {
switch(key) with(Input) switch(key) with(Input)
{ {
@ -594,6 +784,8 @@ Move(FlatBuffer* fb, Input key, Modifier md)
taken = true; taken = true;
} }
} break; } break;
case Home: MoveToSOL(fb); taken = true; break;
case End: MoveToEOL(fb); taken = true; break;
default: break; default: break;
} }
} }
@ -607,20 +799,22 @@ Move(FlatBuffer* fb, Input key, Modifier md)
void void
AdjustOffset(FlatBuffer* fb) AdjustOffset(FlatBuffer* fb)
{ {
with(fb) if(fb.rows > 0) with(fb)
{ {
i64 screen_pos = CurrentLine(fb) - offset; i64 screen_pos = CurrentLine(fb) - offset;
i64 start = 1; i64 start = 0;
i64 end = rows-2; i64 end = rows-2;
if(offset > 0 && screen_pos < start) if(offset > 0 && screen_pos < start)
{ {
offset += screen_pos - start; offset += screen_pos;
} }
else if(screen_pos > end) else if(screen_pos > end)
{ {
offset += screen_pos - end; offset += screen_pos - end;
} }
} }
assert(fb.offset <= fb.lf_count);
} }
void void
@ -708,58 +902,4 @@ unittest
assert(buf.data[i] == ch, "FlatBuffer Replace failure: buffers do not match"); assert(buf.data[i] == ch, "FlatBuffer Replace failure: buffers do not match");
} }
} }
// FlatBuffer lines
{
/*
u8[] data = StringToU8("This is a line.\nThis is a second line,\nalong with a third line.");
FlatBuffer buf = CreateFlatBuffer(data);
assert(buf.lf_count == 3, "FlatBuffer line count mismatch");
u8[] insert = StringToU8("Maybe, ");
Insert(&buf, insert, insert.length, Range(x: 0, y: 1));
string result = "This is a line.\nMaybe, This is a second line,\nalong with a third line.";
foreach(i, ch; result)
{
assert(buf.data[i] == ch, "FlatBuffer Insert pos failure: buffers do not match");
}
u8[][] lines = new u8[][](3, 1024);
GetLines(&buf, lines, 0, 3);
string[] result_arr = [
"This is a line.",
"Maybe, This is a second line,",
"along with a third line.",
];
foreach(i, res; result_arr)
{
foreach(j, ch; res)
{
assert(lines[i][j] == ch, "FlatBuffer GetLines failure: result strings do not match");
}
}
insert = StringToU8("replaced line.\nThis is the previous ");
Insert(&buf, insert, insert.length, Range(x: 10, y: 0));
lines = new u8[][](4, 1024);
GetLines(&buf, lines, 0, 4);
result_arr = [
"This is a replaced line.",
"This is the previous line.",
"Maybe, This is a second line,",
"along with a third line.",
];
foreach(i, res; result_arr)
{
foreach(j, ch; res)
{
assert(lines[i][j] == ch, "FlatBuffer GetLines 2 failure: result strings do not match");
}
}
*/
}
} }