more movement options
This commit is contained in:
parent
9720e22f6a
commit
70f51642cd
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user