aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkoekeishiya <aasvi93@hotmail.com>2017-10-07 23:31:15 +0200
committerkoekeishiya <aasvi93@hotmail.com>2017-10-07 23:31:15 +0200
commit94c26f456f095ec8334d9c313943c2747d27c0c2 (patch)
tree248a10b142f0a59192c931da57643b90ad3b9d4a /src
parent679ae51b23bd936485e1c5c1e868e4dec4995e97 (diff)
downloadskhd-94c26f456f095ec8334d9c313943c2747d27c0c2.tar.gz
skhd-94c26f456f095ec8334d9c313943c2747d27c0c2.zip
#15 modal support
Diffstat (limited to '')
-rw-r--r--src/hotkey.c62
-rw-r--r--src/hotkey.h42
-rw-r--r--src/parse.c147
-rw-r--r--src/parse.h15
-rw-r--r--src/skhd.c21
-rw-r--r--src/tokenize.c27
-rw-r--r--src/tokenize.h6
7 files changed, 265 insertions, 55 deletions
diff --git a/src/hotkey.c b/src/hotkey.c
index d9ebde6..fae753b 100644
--- a/src/hotkey.c
+++ b/src/hotkey.c
@@ -61,6 +61,29 @@ unsigned long hash_hotkey(struct hotkey *a)
return a->key;
}
+bool same_mode(char *a, char *b)
+{
+ while (*a && *b && *a == *b) {
+ ++a;
+ ++b;
+ }
+ return *a == '\0' && *b == '\0';
+}
+
+unsigned long hash_mode(char *key)
+{
+ unsigned long hash = 0, high;
+ while(*key) {
+ hash = (hash << 4) + *key++;
+ high = hash & 0xF0000000;
+ if(high) {
+ hash ^= (high >> 24);
+ }
+ hash &= ~high;
+ }
+ return hash;
+}
+
internal bool
fork_and_exec(char *command)
{
@@ -81,26 +104,36 @@ fork_and_exec(char *command)
return true;
}
-bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *hotkey_map)
+bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *mode_map, struct mode **current_mode)
{
bool result = false;
struct hotkey *hotkey;
- if ((hotkey = table_find(hotkey_map, eventkey))) {
- if (fork_and_exec(hotkey->command)) {
+ if ((hotkey = table_find(&(*current_mode)->hotkey_map, eventkey))) {
+ if (has_flags(hotkey, Hotkey_Flag_Activate)) {
+ *current_mode = table_find(mode_map, hotkey->command);
+ if ((*current_mode)->command) {
+ fork_and_exec((*current_mode)->command);
+ }
+ result = has_flags(hotkey, Hotkey_Flag_Passthrough) ? false : true;
+ } else if (fork_and_exec(hotkey->command)) {
result = has_flags(hotkey, Hotkey_Flag_Passthrough) ? false : true;
}
}
return result;
}
-void free_hotkeys(struct table *hotkey_map)
+internal void
+free_hotkeys(struct table *hotkey_map)
{
int count;
void **hotkeys = table_reset(hotkey_map, &count);
for (int index = 0; index < count; ++index) {
struct hotkey *hotkey = (struct hotkey *) hotkeys[index];
- free(hotkey->command);
- free(hotkey);
+ // the same hotkey can be added for multiple modes
+ // we need to know if this pointer was already freed
+ // by a mode that was destroyed before us
+ // free(hotkey->command);
+ // free(hotkey);
}
if (count) {
@@ -108,6 +141,23 @@ void free_hotkeys(struct table *hotkey_map)
}
}
+void free_mode_map(struct table *mode_map)
+{
+ int count;
+ void **modes = table_reset(mode_map, &count);
+ for (int index = 0; index < count; ++index) {
+ struct mode *mode = (struct mode *) modes[index];
+ if (mode->command) free(mode->command);
+ if (mode->name) free(mode->name);
+ free_hotkeys(&mode->hotkey_map);
+ free(mode);
+ }
+
+ if (count) {
+ free(modes);
+ }
+}
+
internal void
cgevent_lrmod_flag_to_hotkey_lrmod_flag(CGEventFlags flags, struct hotkey *eventkey, int mod)
{
diff --git a/src/hotkey.h b/src/hotkey.h
index 40ea630..530520b 100644
--- a/src/hotkey.h
+++ b/src/hotkey.h
@@ -24,31 +24,45 @@ enum osx_event_mask
enum hotkey_flag
{
- Hotkey_Flag_Alt = (1 << 0),
- Hotkey_Flag_LAlt = (1 << 1),
- Hotkey_Flag_RAlt = (1 << 2),
- Hotkey_Flag_Shift = (1 << 3),
- Hotkey_Flag_LShift = (1 << 4),
- Hotkey_Flag_RShift = (1 << 5),
- Hotkey_Flag_Cmd = (1 << 6),
- Hotkey_Flag_LCmd = (1 << 7),
- Hotkey_Flag_RCmd = (1 << 8),
- Hotkey_Flag_Control = (1 << 9),
+ Hotkey_Flag_Alt = (1 << 0),
+ Hotkey_Flag_LAlt = (1 << 1),
+ Hotkey_Flag_RAlt = (1 << 2),
+ Hotkey_Flag_Shift = (1 << 3),
+ Hotkey_Flag_LShift = (1 << 4),
+ Hotkey_Flag_RShift = (1 << 5),
+ Hotkey_Flag_Cmd = (1 << 6),
+ Hotkey_Flag_LCmd = (1 << 7),
+ Hotkey_Flag_RCmd = (1 << 8),
+ Hotkey_Flag_Control = (1 << 9),
Hotkey_Flag_LControl = (1 << 10),
Hotkey_Flag_RControl = (1 << 11),
Hotkey_Flag_Fn = (1 << 12),
Hotkey_Flag_Passthrough = (1 << 13),
+ Hotkey_Flag_Activate = (1 << 14),
Hotkey_Flag_Hyper = (Hotkey_Flag_Cmd |
Hotkey_Flag_Alt |
Hotkey_Flag_Shift |
Hotkey_Flag_Control)
};
+#include "hashtable.h"
+
+struct mode
+{
+ int line;
+ int cursor;
+ char *name;
+ char *command;
+ struct table hotkey_map;
+};
+
struct hotkey
{
uint32_t flags;
uint32_t key;
char *command;
+ int mode_count;
+ struct mode *mode_list[16];
};
static inline void
@@ -70,13 +84,15 @@ clear_flags(struct hotkey *hotkey, uint32_t flag)
hotkey->flags &= ~flag;
}
+bool same_mode(char *a, char *b);
+unsigned long hash_mode(char *key);
+
bool same_hotkey(struct hotkey *a, struct hotkey *b);
unsigned long hash_hotkey(struct hotkey *a);
-bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *hotkey_map);
+bool find_and_exec_hotkey(struct hotkey *eventkey, struct table *mode_map, struct mode **current_mode);
void cgeventflags_to_hotkeyflags(CGEventFlags flags, struct hotkey *eventkey);
-struct table;
-void free_hotkeys(struct table *hotkey_map);
+void free_mode_map(struct table *mode_map);
#endif
diff --git a/src/parse.c b/src/parse.c
index 6a12963..bf5a48d 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -137,34 +137,75 @@ parse_modifier(struct parser *parser)
if (parser_match(parser, Token_Modifier)) {
flags |= parse_modifier(parser);
} else {
- parser_report_error(parser, "expected modifier");
+ parser_report_error(parser, Error_Unexpected_Token, "expected modifier");
}
}
return flags;
}
+internal void
+parse_mode(struct parser *parser, struct hotkey *hotkey)
+{
+ struct token identifier = parser_previous(parser);
+
+ char *name = copy_string_count(identifier.text, identifier.length);
+ struct mode *mode = table_find(parser->mode_map, name);
+ free(name);
+
+ if (!mode) {
+ parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier");
+ return;
+ }
+
+ hotkey->mode_list[hotkey->mode_count++] = mode;
+ printf("\tmode: '%s'\n", mode->name);
+
+ if (parser_match(parser, Token_Comma)) {
+ if (parser_match(parser, Token_Identifier)) {
+ parse_mode(parser, hotkey);
+ } else {
+ parser_report_error(parser, Error_Unexpected_Token, "expected identifier");
+ return;
+ }
+ }
+}
+
internal struct hotkey *
parse_hotkey(struct parser *parser)
{
struct hotkey *hotkey = malloc(sizeof(struct hotkey));
- int found_modifier;
+ memset(hotkey, 0, sizeof(struct hotkey));
+ bool found_modifier;
printf("(#%d) hotkey :: {\n", parser->current_token.line);
- if (parser_match(parser, Token_Modifier)) {
- hotkey->flags = parse_modifier(parser);
+ if (parser_match(parser, Token_Identifier)) {
+ parse_mode(parser, hotkey);
if (parser->error) {
return NULL;
}
- found_modifier = 1;
+ }
+
+ if (hotkey->mode_count > 0) {
+ if (!parser_match(parser, Token_Insert)) {
+ parser_report_error(parser, Error_Unexpected_Token, "expected '<'");
+ return NULL;
+ }
} else {
- hotkey->flags = found_modifier = 0;
+ hotkey->mode_list[hotkey->mode_count++] = table_find(parser->mode_map, "default");
+ }
+
+ if ((found_modifier = parser_match(parser, Token_Modifier))) {
+ hotkey->flags = parse_modifier(parser);
+ if (parser->error) {
+ return NULL;
+ }
}
if (found_modifier) {
if (!parser_match(parser, Token_Dash)) {
- parser_report_error(parser, "expected '-'");
+ parser_report_error(parser, Error_Unexpected_Token, "expected '-'");
return NULL;
}
}
@@ -176,7 +217,7 @@ parse_hotkey(struct parser *parser)
} else if (parser_match(parser, Token_Literal)) {
parse_key_literal(parser, hotkey);
} else {
- parser_report_error(parser, "expected key-literal");
+ parser_report_error(parser, Error_Unexpected_Token, "expected key-literal");
return NULL;
}
@@ -186,8 +227,15 @@ parse_hotkey(struct parser *parser)
if (parser_match(parser, Token_Command)) {
hotkey->command = parse_command(parser);
+ } else if (parser_match(parser, Token_Activate)) {
+ hotkey->flags |= Hotkey_Flag_Activate;
+ hotkey->command = parse_command(parser);
+ if (!table_find(parser->mode_map, hotkey->command)) {
+ parser_report_error(parser, Error_Undeclared_Ident, "undeclared identifier");
+ return NULL;
+ }
} else {
- parser_report_error(parser, "expected ':' followed by command");
+ parser_report_error(parser, Error_Unexpected_Token, "expected ':' followed by command or ';' followed by mode");
return NULL;
}
@@ -196,22 +244,69 @@ parse_hotkey(struct parser *parser)
return hotkey;
}
-void parse_config(struct parser *parser, struct table *hotkey_map)
+internal struct mode *
+parse_mode_decl(struct parser *parser)
+{
+ /* :: focus : chunkc border::color 0xff202020 */
+ struct mode *mode = malloc(sizeof(struct mode));
+
+ struct token identifier = parser_previous(parser);
+ mode->line = identifier.line;
+ mode->cursor = identifier.cursor;
+ mode->name = copy_string_count(identifier.text, identifier.length);
+
+ table_init(&mode->hotkey_map,
+ 131,
+ (table_hash_func) hash_hotkey,
+ (table_compare_func) same_hotkey);
+
+ if (parser_match(parser, Token_Command)) {
+ mode->command = copy_string_count(parser->previous_token.text, parser->previous_token.length);
+ } else {
+ mode->command = NULL;
+ }
+
+ return mode;
+}
+
+void parse_config(struct parser *parser)
{
+ struct mode *mode;
struct hotkey *hotkey;
+
while (!parser_eof(parser)) {
- if ((parser_check(parser, Token_Modifier)) ||
- (parser_check(parser, Token_Literal)) ||
- (parser_check(parser, Token_Key_Hex)) ||
- (parser_check(parser, Token_Key))) {
+ if (parser_match(parser, Token_Decl)) {
+ if (parser_match(parser, Token_Identifier)) {
+ mode = parse_mode_decl(parser);
+ if (table_find(parser->mode_map, mode->name)) {
+ parser_report_error(parser, Error_Duplicate_Ident,
+ "(#%d:%d) duplicate declaration '%s'\n",
+ mode->line, mode->cursor, mode->name);
+ return;
+ } else {
+ table_add(parser->mode_map, mode->name, mode);
+ }
+ } else {
+ parser_report_error(parser, Error_Unexpected_Token, "expected identifier");
+ return;
+ }
+ } else if ((parser_check(parser, Token_Identifier)) ||
+ (parser_check(parser, Token_Modifier)) ||
+ (parser_check(parser, Token_Literal)) ||
+ (parser_check(parser, Token_Key_Hex)) ||
+ (parser_check(parser, Token_Key))) {
hotkey = parse_hotkey(parser);
if (parser->error) {
- free_hotkeys(hotkey_map);
+ free_mode_map(parser->mode_map);
return;
}
- table_add(hotkey_map, hotkey, hotkey);
+
+ for (int i = 0; i < hotkey->mode_count; ++i) {
+ mode = hotkey->mode_list[i];
+ table_add(&mode->hotkey_map, hotkey, hotkey);
+ }
} else {
- parser_report_error(parser, "expected modifier or key-literal");
+ parser_report_error(parser, Error_Unexpected_Token, "expected decl, modifier or key-literal");
return;
}
}
@@ -261,13 +356,23 @@ bool parser_match(struct parser *parser, enum token_type type)
return false;
}
-void parser_report_error(struct parser *parser, const char *format, ...)
+void parser_report_error(struct parser *parser, enum parse_error_type error_type, const char *format, ...)
{
va_list args;
va_start(args, format);
- fprintf(stderr, "(#%d:%d) ", parser->current_token.line, parser->current_token.cursor);
- vfprintf(stderr, format, args);
- fprintf(stderr, ", but got '%.*s'\n", parser->current_token.length, parser->current_token.text);
+
+ if (error_type == Error_Unexpected_Token) {
+ fprintf(stderr, "(#%d:%d) ", parser->current_token.line, parser->current_token.cursor);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, ", but got '%.*s'\n", parser->current_token.length, parser->current_token.text);
+ } else if (error_type == Error_Undeclared_Ident) {
+ fprintf(stderr, "(#%d:%d) ", parser->previous_token.line, parser->previous_token.cursor);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, " '%.*s'\n", parser->previous_token.length, parser->previous_token.text);
+ } else if (error_type == Error_Duplicate_Ident) {
+ vfprintf(stderr, format, args);
+ }
+
va_end(args);
parser->error = true;
}
diff --git a/src/parse.h b/src/parse.h
index 241e7ff..1c7719d 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -4,16 +4,25 @@
#include "tokenize.h"
#include <stdbool.h>
+struct table;
struct parser
{
struct token previous_token;
struct token current_token;
struct tokenizer tokenizer;
+ struct table *mode_map;
bool error;
};
-struct table;
-void parse_config(struct parser *parser, struct table *hotkey_map);
+enum parse_error_type
+{
+ Error_Unexpected_Token,
+ Error_Undeclared_Ident,
+ Error_Duplicate_Ident,
+};
+
+
+void parse_config(struct parser *parser);
struct token parser_peek(struct parser *parser);
struct token parser_previous(struct parser *parser);
@@ -23,6 +32,6 @@ bool parser_check(struct parser *parser, enum token_type type);
bool parser_match(struct parser *parser, enum token_type type);
bool parser_init(struct parser *parser, char *file);
void parser_destroy(struct parser *parser);
-void parser_report_error(struct parser *parser, const char *format, ...);
+void parser_report_error(struct parser *parser, enum parse_error_type error_type, const char *format, ...);
#endif
diff --git a/src/skhd.c b/src/skhd.c
index 3e2b072..a8c02e6 100644
--- a/src/skhd.c
+++ b/src/skhd.c
@@ -42,7 +42,8 @@ extern bool CGSIsSecureEventInputSet();
internal unsigned major_version = 0;
internal unsigned minor_version = 0;
internal unsigned patch_version = 10;
-internal struct table hotkey_map;
+internal struct mode *current_mode;
+internal struct table mode_map;
internal char *config_file;
internal void
@@ -69,16 +70,19 @@ parse_config_helper(char *absolutepath)
{
struct parser parser;
if (parser_init(&parser, absolutepath)) {
- parse_config(&parser, &hotkey_map);
+ parser.mode_map = &mode_map;
+ parse_config(&parser);
parser_destroy(&parser);
+ current_mode = table_find(&mode_map, "default");
} else {
+ current_mode = NULL;
warn("skhd: could not open file '%s'\n", absolutepath);
}
}
internal HOTLOADER_CALLBACK(config_handler)
{
- free_hotkeys(&hotkey_map);
+ free_mode_map(&mode_map);
parse_config_helper(absolutepath);
}
@@ -92,11 +96,12 @@ internal EVENT_TAP_CALLBACK(key_handler)
CGEventTapEnable(event_tap->handle, 1);
} break;
case kCGEventKeyDown: {
+ if (!current_mode) return event;
uint32_t flags = CGEventGetFlags(event);
uint32_t key = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
struct hotkey eventkey = { .flags = 0, .key = key };
cgeventflags_to_hotkeyflags(flags, &eventkey);
- bool result = find_and_exec_hotkey(&eventkey, &hotkey_map);
+ bool result = find_and_exec_hotkey(&eventkey, &mode_map, &current_mode);
if (result) {
return NULL;
}
@@ -186,10 +191,10 @@ int main(int argc, char **argv)
set_config_path();
}
- table_init(&hotkey_map,
- 131,
- (table_hash_func) hash_hotkey,
- (table_compare_func) same_hotkey);
+ table_init(&mode_map,
+ 13,
+ (table_hash_func) hash_mode,
+ (table_compare_func) same_mode);
printf("skhd: using config '%s'\n", config_file);
parse_config_helper(config_file);
diff --git a/src/tokenize.c b/src/tokenize.c
index 691b9c8..82cd466 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -94,7 +94,7 @@ resolve_identifier_type(struct token token)
}
}
- return Token_Unknown;
+ return Token_Identifier;
}
struct token
@@ -121,6 +121,8 @@ get_token(struct tokenizer *tokenizer)
switch (c) {
case '\0':{ token.type = Token_EndOfStream; } break;
case '+': { token.type = Token_Plus; } break;
+ case ',': { token.type = Token_Comma; } break;
+ case '<': { token.type = Token_Insert; } break;
case '#': {
eat_comment(tokenizer);
token = get_token(tokenizer);
@@ -134,16 +136,33 @@ get_token(struct tokenizer *tokenizer)
token.type = Token_Dash;
}
} break;
- case ':': {
+ case ';': {
eat_whitespace(tokenizer);
token.text = tokenizer->at;
token.line = tokenizer->line;
token.cursor = tokenizer->cursor;
- eat_command(tokenizer);
+ eat_identifier(tokenizer);
token.length = tokenizer->at - token.text;
- token.type = Token_Command;
+ token.type = Token_Activate;
+ } break;
+ case ':': {
+ if (*tokenizer->at && *tokenizer->at == ':') {
+ advance(tokenizer);
+ token.length = tokenizer->at - token.text;
+ token.type = Token_Decl;
+ } else {
+ eat_whitespace(tokenizer);
+
+ token.text = tokenizer->at;
+ token.line = tokenizer->line;
+ token.cursor = tokenizer->cursor;
+
+ eat_command(tokenizer);
+ token.length = tokenizer->at - token.text;
+ token.type = Token_Command;
+ }
} break;
default: {
if (c == '0' && *tokenizer->at == 'x') {
diff --git a/src/tokenize.h b/src/tokenize.h
index 36b4350..114ed0d 100644
--- a/src/tokenize.h
+++ b/src/tokenize.h
@@ -28,12 +28,18 @@ static const char *literal_keycode_str[] =
enum token_type
{
+ Token_Identifier,
+ Token_Activate,
+
Token_Command,
Token_Modifier,
Token_Literal,
Token_Key_Hex,
Token_Key,
+ Token_Decl,
+ Token_Comma,
+ Token_Insert,
Token_Plus,
Token_Dash,
Token_Arrow,