: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?
|
||||
! 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:
|
||||
- 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;
|
||||
}
|
||||
|
||||
API String SkipNumberEx(String *string) {
|
||||
API String SkipIntEx(String *string) {
|
||||
String col = {string->data, 0};
|
||||
for (int64_t i = 0; i < string->len; i += 1) {
|
||||
if (IsDigit(string->data[i])) {
|
||||
@@ -391,8 +391,8 @@ API String SkipNumberEx(String *string) {
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int SkipNumber(String *string) {
|
||||
String col = SkipNumberEx(string);
|
||||
API Int SkipInt(String *string) {
|
||||
String col = SkipIntEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
Int result = strtoll(col.data, NULL, 10);
|
||||
return result;
|
||||
|
||||
@@ -384,8 +384,12 @@ API Int GetSize(Array<String16> array) {
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipNumberEx(String16 *string) {
|
||||
API String16 SkipIntEx(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])) {
|
||||
col.len += 1;
|
||||
@@ -397,15 +401,41 @@ API String16 SkipNumberEx(String16 *string) {
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int SkipNumber(String16 *string) {
|
||||
String16 col = SkipNumberEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
API Int SkipInt(String16 *string) {
|
||||
String16 col = SkipIntEx(string);
|
||||
if (col.len == 0) return 0;
|
||||
Scratch scratch;
|
||||
String num_string = ToString(scratch, col);
|
||||
Int result = strtoll(num_string.data, NULL, 10);
|
||||
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) {
|
||||
String16 begin = *string;
|
||||
begin.len = 0;
|
||||
@@ -419,14 +449,31 @@ API String16 SkipUntil(String16 *string, String16 str) {
|
||||
|
||||
API String16 SkipWhitespace(String16 *string) {
|
||||
String16 begin = {string->data, 0};
|
||||
for (Int i = 0; i < string->len; i += 1) {
|
||||
if (!IsWhitespace(string->data[i])) break;
|
||||
for (;string->len;) {
|
||||
if (!IsWhitespace(At(*string, 0))) {
|
||||
break;
|
||||
}
|
||||
*string = Skip(*string, 1);
|
||||
begin.len += 1;
|
||||
}
|
||||
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) {
|
||||
if (EndsWith(*string, ending)) {
|
||||
*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);
|
||||
|
||||
// @todo: think about this API, for parsing, maybe redesign or something
|
||||
API String16 SkipNumberEx(String16 *string);
|
||||
API Int SkipNumber(String16 *string);
|
||||
API String16 SkipIntEx(String16 *string);
|
||||
API Int SkipInt(String16 *string);
|
||||
API String16 SkipUntil(String16 *string, String16 str);
|
||||
API String16 SkipWhitespace(String16 *string);
|
||||
API String16 ChopNumberEx(String16 *string);
|
||||
|
||||
@@ -167,7 +167,7 @@ void UIMessagef(const char *fmt, ...) {
|
||||
NextActiveWindowID = main.window->id;
|
||||
RawAppendf(main.buffer, "\n %S\n :Close\n", string);
|
||||
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);
|
||||
Close(active.buffer->id);
|
||||
});
|
||||
@@ -179,7 +179,6 @@ void ReportErrorf(const char *fmt, ...) {
|
||||
View *view = GetView(NullViewID);
|
||||
if (view) {
|
||||
Appendf(view, "%S\n", string);
|
||||
NextActiveWindowID = NullWindowID;
|
||||
}
|
||||
UIMessagef("%S", string);
|
||||
}
|
||||
@@ -526,18 +525,18 @@ ResolvedOpen ResolveOpen(Allocator alo, String path, String meta) {
|
||||
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipNumber(&p);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ':') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipNumber(&p);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
} else if (At(p, 0) == '(') {
|
||||
p = Skip(p, 1);
|
||||
result.line = SkipNumber(&p);
|
||||
result.line = SkipInt(&p);
|
||||
if (At(p, 0) == ',') {
|
||||
p = Skip(p, 1);
|
||||
Int b = SkipNumber(&p);
|
||||
Int b = SkipInt(&p);
|
||||
result.col = b;
|
||||
}
|
||||
}
|
||||
@@ -1245,3 +1244,108 @@ void Command_ClearCarets() {
|
||||
}
|
||||
}
|
||||
} 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