:Set command

This commit is contained in:
Krzosa Karol
2025-12-31 11:50:21 +01:00
parent 0921054b6e
commit b40873d54c
5 changed files with 172 additions and 17 deletions

View File

@@ -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?

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 = &it;
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 = &it;
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, "");