:Set command
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
! What precise workflow do I need for me to be viable to use this?
|
! What precise workflow do I need for me to be viable to use this?
|
||||||
! From a user (novice) point of view, how does it look like?
|
! From a user (novice) point of view, how does it look like?
|
||||||
|
|
||||||
|
- Make all the keybinding / hook parsing initialize at the start to reduce runtime problems
|
||||||
|
- RegisterCommand should_appear_in_listing variable
|
||||||
|
- Maybe one list for all variables including the commands etc?
|
||||||
|
- make variables nicer named
|
||||||
|
|
||||||
Use session 3:
|
Use session 3:
|
||||||
- Maybe status view, commit changes (like to buffer name or line) on enter?
|
- Maybe status view, commit changes (like to buffer name or line) on enter?
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ API bool Chop(String *string, String ending) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
API String SkipNumberEx(String *string) {
|
API String SkipIntEx(String *string) {
|
||||||
String col = {string->data, 0};
|
String col = {string->data, 0};
|
||||||
for (int64_t i = 0; i < string->len; i += 1) {
|
for (int64_t i = 0; i < string->len; i += 1) {
|
||||||
if (IsDigit(string->data[i])) {
|
if (IsDigit(string->data[i])) {
|
||||||
@@ -391,8 +391,8 @@ API String SkipNumberEx(String *string) {
|
|||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
API Int SkipNumber(String *string) {
|
API Int SkipInt(String *string) {
|
||||||
String col = SkipNumberEx(string);
|
String col = SkipIntEx(string);
|
||||||
if (col.len == 0) return -1;
|
if (col.len == 0) return -1;
|
||||||
Int result = strtoll(col.data, NULL, 10);
|
Int result = strtoll(col.data, NULL, 10);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -384,8 +384,12 @@ API Int GetSize(Array<String16> array) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
API String16 SkipNumberEx(String16 *string) {
|
API String16 SkipIntEx(String16 *string) {
|
||||||
String16 col = {string->data, 0};
|
String16 col = {string->data, 0};
|
||||||
|
if (At(*string, 0) == '-') {
|
||||||
|
col.len += 1;
|
||||||
|
*string = Skip(*string, 1);
|
||||||
|
}
|
||||||
for (int64_t i = 0; i < string->len; i += 1) {
|
for (int64_t i = 0; i < string->len; i += 1) {
|
||||||
if (IsDigit(string->data[i])) {
|
if (IsDigit(string->data[i])) {
|
||||||
col.len += 1;
|
col.len += 1;
|
||||||
@@ -397,15 +401,41 @@ API String16 SkipNumberEx(String16 *string) {
|
|||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
API Int SkipNumber(String16 *string) {
|
API Int SkipInt(String16 *string) {
|
||||||
String16 col = SkipNumberEx(string);
|
String16 col = SkipIntEx(string);
|
||||||
if (col.len == 0) return -1;
|
if (col.len == 0) return 0;
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
String num_string = ToString(scratch, col);
|
String num_string = ToString(scratch, col);
|
||||||
Int result = strtoll(num_string.data, NULL, 10);
|
Int result = strtoll(num_string.data, NULL, 10);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
API String16 SkipFloatEx(String16 *string) {
|
||||||
|
String16 col = {string->data, 0};
|
||||||
|
if (At(*string, 0) == '-') {
|
||||||
|
col.len += 1;
|
||||||
|
*string = Skip(*string, 1);
|
||||||
|
}
|
||||||
|
for (int64_t i = 0; i < string->len; i += 1) {
|
||||||
|
if (IsDigit(string->data[i]) || string->data[i] == u'.') {
|
||||||
|
col.len += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*string = Skip(*string, col.len);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
API Float SkipFloat(String16 *string) {
|
||||||
|
String16 col = SkipFloatEx(string);
|
||||||
|
if (col.len == 0) return 0;
|
||||||
|
Scratch scratch;
|
||||||
|
String num_string = ToString(scratch, col);
|
||||||
|
Float result = strtod(num_string.data, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
API String16 SkipUntil(String16 *string, String16 str) {
|
API String16 SkipUntil(String16 *string, String16 str) {
|
||||||
String16 begin = *string;
|
String16 begin = *string;
|
||||||
begin.len = 0;
|
begin.len = 0;
|
||||||
@@ -419,14 +449,31 @@ API String16 SkipUntil(String16 *string, String16 str) {
|
|||||||
|
|
||||||
API String16 SkipWhitespace(String16 *string) {
|
API String16 SkipWhitespace(String16 *string) {
|
||||||
String16 begin = {string->data, 0};
|
String16 begin = {string->data, 0};
|
||||||
for (Int i = 0; i < string->len; i += 1) {
|
for (;string->len;) {
|
||||||
if (!IsWhitespace(string->data[i])) break;
|
if (!IsWhitespace(At(*string, 0))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
*string = Skip(*string, 1);
|
*string = Skip(*string, 1);
|
||||||
begin.len += 1;
|
begin.len += 1;
|
||||||
}
|
}
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String16 SkipIdent(String16 *string) {
|
||||||
|
String16 begin = {string->data, 0};
|
||||||
|
if (IsIdent(At(*string, 0))) {
|
||||||
|
for (;string->len;) {
|
||||||
|
char16_t c = At(*string, 0);
|
||||||
|
if (!IsIdent(c) && !IsDigit(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*string = Skip(*string, 1);
|
||||||
|
begin.len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
API bool Chop(String16 *string, String16 ending) {
|
API bool Chop(String16 *string, String16 ending) {
|
||||||
if (EndsWith(*string, ending)) {
|
if (EndsWith(*string, ending)) {
|
||||||
*string = Chop(*string, ending.len);
|
*string = Chop(*string, ending.len);
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ API String16 CutPrefix(String16 *string, int64_t len);
|
|||||||
API String16 CutPostfix(String16 *string, int64_t len);
|
API String16 CutPostfix(String16 *string, int64_t len);
|
||||||
|
|
||||||
// @todo: think about this API, for parsing, maybe redesign or something
|
// @todo: think about this API, for parsing, maybe redesign or something
|
||||||
API String16 SkipNumberEx(String16 *string);
|
API String16 SkipIntEx(String16 *string);
|
||||||
API Int SkipNumber(String16 *string);
|
API Int SkipInt(String16 *string);
|
||||||
API String16 SkipUntil(String16 *string, String16 str);
|
API String16 SkipUntil(String16 *string, String16 str);
|
||||||
API String16 SkipWhitespace(String16 *string);
|
API String16 SkipWhitespace(String16 *string);
|
||||||
API String16 ChopNumberEx(String16 *string);
|
API String16 ChopNumberEx(String16 *string);
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ void UIMessagef(const char *fmt, ...) {
|
|||||||
NextActiveWindowID = main.window->id;
|
NextActiveWindowID = main.window->id;
|
||||||
RawAppendf(main.buffer, "\n %S\n :Close\n", string);
|
RawAppendf(main.buffer, "\n %S\n :Close\n", string);
|
||||||
main.view->carets[0] = FindNext(main.buffer, u":Close", MakeCaret(0));
|
main.view->carets[0] = FindNext(main.buffer, u":Close", MakeCaret(0));
|
||||||
AddHook(&main.view->hooks, "Close", "escape", [](){
|
AddHook(&main.view->hooks, "Close", "escape | enter", [](){
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
BSet active = GetBSet(ActiveWindowID);
|
||||||
Close(active.buffer->id);
|
Close(active.buffer->id);
|
||||||
});
|
});
|
||||||
@@ -179,7 +179,6 @@ void ReportErrorf(const char *fmt, ...) {
|
|||||||
View *view = GetView(NullViewID);
|
View *view = GetView(NullViewID);
|
||||||
if (view) {
|
if (view) {
|
||||||
Appendf(view, "%S\n", string);
|
Appendf(view, "%S\n", string);
|
||||||
NextActiveWindowID = NullWindowID;
|
|
||||||
}
|
}
|
||||||
UIMessagef("%S", string);
|
UIMessagef("%S", string);
|
||||||
}
|
}
|
||||||
@@ -526,18 +525,18 @@ ResolvedOpen ResolveOpen(Allocator alo, String path, String meta) {
|
|||||||
|
|
||||||
if (At(p, 0) == ':') {
|
if (At(p, 0) == ':') {
|
||||||
p = Skip(p, 1);
|
p = Skip(p, 1);
|
||||||
result.line = SkipNumber(&p);
|
result.line = SkipInt(&p);
|
||||||
if (At(p, 0) == ':') {
|
if (At(p, 0) == ':') {
|
||||||
p = Skip(p, 1);
|
p = Skip(p, 1);
|
||||||
Int b = SkipNumber(&p);
|
Int b = SkipInt(&p);
|
||||||
result.col = b;
|
result.col = b;
|
||||||
}
|
}
|
||||||
} else if (At(p, 0) == '(') {
|
} else if (At(p, 0) == '(') {
|
||||||
p = Skip(p, 1);
|
p = Skip(p, 1);
|
||||||
result.line = SkipNumber(&p);
|
result.line = SkipInt(&p);
|
||||||
if (At(p, 0) == ',') {
|
if (At(p, 0) == ',') {
|
||||||
p = Skip(p, 1);
|
p = Skip(p, 1);
|
||||||
Int b = SkipNumber(&p);
|
Int b = SkipInt(&p);
|
||||||
result.col = b;
|
result.col = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1245,3 +1244,108 @@ void Command_ClearCarets() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} RegisterCommand(Command_ClearCarets, "escape");
|
} RegisterCommand(Command_ClearCarets, "escape");
|
||||||
|
|
||||||
|
void Command_Set() {
|
||||||
|
Scratch scratch;
|
||||||
|
BSet set = GetBSet(ActiveWindowID);
|
||||||
|
Range range = set.view->carets[0].range;
|
||||||
|
if (GetSize(range) == 0) {
|
||||||
|
range = EncloseLoadWord(set.buffer, range.min);
|
||||||
|
}
|
||||||
|
Int line_end = GetLineEnd(set.buffer, range.min);
|
||||||
|
String16 string = GetString(set.buffer, {range.max, line_end});
|
||||||
|
|
||||||
|
SkipWhitespace(&string);
|
||||||
|
String16 name = SkipIdent(&string);
|
||||||
|
if (name.len == 0) {
|
||||||
|
ReportErrorf("Set command failed to parse at the variable name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name8 = ToString(scratch, name);
|
||||||
|
Variable *var = NULL;
|
||||||
|
For (Variables) {
|
||||||
|
if (name8 == it.name) {
|
||||||
|
var = ⁢
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var) {
|
||||||
|
SkipWhitespace(&string);
|
||||||
|
if (var->type == VariableType_String) {
|
||||||
|
char16_t c = At(string, 0);
|
||||||
|
String16 q = {&c, 1};
|
||||||
|
if (c == u'"' || c == u'\'') {
|
||||||
|
string = Skip(string, 1);
|
||||||
|
String16 quote = SkipUntil(&string, q);
|
||||||
|
if (At(string, 0) != c) {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <error here>, unclosed quote", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String quote8 = ToString(scratch, quote);
|
||||||
|
ReportConsolef(":Set %S %c%S%c", name8, c, quote8, c);
|
||||||
|
*var->string = Intern(&GlobalInternTable, quote8);
|
||||||
|
} else {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <expected string>", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (var->type == VariableType_Int) {
|
||||||
|
if (IsDigit(At(string, 0))) {
|
||||||
|
Int number = SkipInt(&string);
|
||||||
|
ReportConsolef(":Set %S %lld", name8, number);
|
||||||
|
*var->i = number;
|
||||||
|
} else {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <expected integer>", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (var->type == VariableType_Float) {
|
||||||
|
if (IsDigit(At(string, 0)) || At(string, 0) == '.') {
|
||||||
|
Float number = SkipFloat(&string);
|
||||||
|
ReportConsolef(":Set %S %f", name8, number);
|
||||||
|
*var->f = number;
|
||||||
|
} else {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <expected float>", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} ElseInvalidCodepath();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandData *cmd = NULL;
|
||||||
|
For (CommandFunctions) {
|
||||||
|
if (it.name == name8) {
|
||||||
|
cmd = ⁢
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd) {
|
||||||
|
SkipWhitespace(&string);
|
||||||
|
char16_t c = At(string, 0);
|
||||||
|
String16 q = {&c, 1};
|
||||||
|
if (c == u'"' || c == u'\'') {
|
||||||
|
string = Skip(string, 1);
|
||||||
|
String16 quote = SkipUntil(&string, q);
|
||||||
|
if (At(string, 0) != c) {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <error here>, unclosed quote", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String quote8 = Intern(&GlobalInternTable, ToString(scratch, quote));
|
||||||
|
ReportConsolef(":Set %S %c%S%c", name8, c, quote8, c);
|
||||||
|
Trigger *trigger = ParseKeyCached(quote8);
|
||||||
|
if (trigger) {
|
||||||
|
cmd->binding = quote8;
|
||||||
|
cmd->trigger = trigger;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ReportErrorf("Failed to parse :Set %S <expected string>", name8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReportErrorf("Failed to :Set, no such variable found: %S", name8);
|
||||||
|
} RegisterCommand(Command_Set, "");
|
||||||
Reference in New Issue
Block a user