more movement options
This commit is contained in:
parent
9720e22f6a
commit
70f51642cd
@ -3,6 +3,7 @@ import core.stdc.stdio : EOF;
|
||||
import parsing;
|
||||
import std.format : sformat;
|
||||
import std.math.algebraic : abs;
|
||||
import editor;
|
||||
|
||||
struct FlatBuffer
|
||||
{
|
||||
@ -48,6 +49,41 @@ enum WalkDir
|
||||
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
|
||||
CreateFlatBuffer(u8[] data)
|
||||
{
|
||||
@ -94,10 +130,7 @@ CountLF(u8[] data)
|
||||
u64 lf_count = 0;
|
||||
for(u64 i = 0; i < data.length; i += 1)
|
||||
{
|
||||
if(data.ptr[i] == '\n')
|
||||
{
|
||||
lf_count += 1;
|
||||
}
|
||||
lf_count += u64(data.ptr[i] == '\n');
|
||||
}
|
||||
|
||||
return lf_count;
|
||||
@ -183,11 +216,7 @@ Insert(FlatBuffer* fb, u8[] insert, u64 length, u64 pos)
|
||||
for(u64 i = 0; i < length; i += 1)
|
||||
{
|
||||
fb.buf_pos += 1;
|
||||
|
||||
if(insert.ptr[i] == '\n')
|
||||
{
|
||||
fb.lf_count += 1;
|
||||
}
|
||||
fb.lf_count += u64(insert.ptr[i] == '\n');
|
||||
}
|
||||
|
||||
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
|
||||
Move(FlatBuffer* fb, Input key, Modifier md)
|
||||
{
|
||||
bool taken;
|
||||
|
||||
switch(key) with(Input)
|
||||
{
|
||||
case Home: MoveToSOL(fb); taken = true; break;
|
||||
case End: MoveToEOL(fb); taken = true; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(!taken && md & (MD.LeftShift | MD.RightShift))
|
||||
if(md & (MD.LeftShift | MD.RightShift))
|
||||
{
|
||||
switch(key) with(Input)
|
||||
{
|
||||
@ -533,16 +710,24 @@ Move(FlatBuffer* fb, Input key, Modifier md)
|
||||
} break;
|
||||
case Left:
|
||||
{
|
||||
|
||||
if(fb.buf_pos > 0)
|
||||
{
|
||||
MoveToWordEdge!(false)(fb);
|
||||
}
|
||||
} break;
|
||||
case Right:
|
||||
{
|
||||
|
||||
if(fb.buf_pos < fb.length)
|
||||
{
|
||||
MoveToWordEdge!(true)(fb);
|
||||
}
|
||||
} break;
|
||||
case Home: fb.buf_pos = 0; taken = true; break;
|
||||
case End: fb.buf_pos = fb.length; taken = true; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if(!taken && md & (MD.LeftCtrl | MD.RightCtrl))
|
||||
else if(md & (MD.LeftCtrl | MD.RightCtrl))
|
||||
{
|
||||
switch(key) with(Input)
|
||||
{
|
||||
@ -551,20 +736,25 @@ Move(FlatBuffer* fb, Input key, Modifier md)
|
||||
} break;
|
||||
case Down:
|
||||
{
|
||||
|
||||
} break;
|
||||
case Left:
|
||||
{
|
||||
|
||||
if(fb.buf_pos > 0)
|
||||
{
|
||||
MoveToNextWord!(false)(fb);
|
||||
}
|
||||
} break;
|
||||
case Right:
|
||||
{
|
||||
|
||||
if(fb.buf_pos < fb.length)
|
||||
{
|
||||
MoveToNextWord!(true)(fb);
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if(!taken)
|
||||
else
|
||||
{
|
||||
switch(key) with(Input)
|
||||
{
|
||||
@ -594,6 +784,8 @@ Move(FlatBuffer* fb, Input key, Modifier md)
|
||||
taken = true;
|
||||
}
|
||||
} break;
|
||||
case Home: MoveToSOL(fb); taken = true; break;
|
||||
case End: MoveToEOL(fb); taken = true; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -607,20 +799,22 @@ Move(FlatBuffer* fb, Input key, Modifier md)
|
||||
void
|
||||
AdjustOffset(FlatBuffer* fb)
|
||||
{
|
||||
with(fb)
|
||||
if(fb.rows > 0) with(fb)
|
||||
{
|
||||
i64 screen_pos = CurrentLine(fb) - offset;
|
||||
i64 start = 1;
|
||||
i64 start = 0;
|
||||
i64 end = rows-2;
|
||||
if(offset > 0 && screen_pos < start)
|
||||
{
|
||||
offset += screen_pos - start;
|
||||
offset += screen_pos;
|
||||
}
|
||||
else if(screen_pos > end)
|
||||
{
|
||||
offset += screen_pos - end;
|
||||
}
|
||||
}
|
||||
|
||||
assert(fb.offset <= fb.lf_count);
|
||||
}
|
||||
|
||||
void
|
||||
@ -708,58 +902,4 @@ unittest
|
||||
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