Skip to content

Commit

Permalink
style override by switches
Browse files Browse the repository at this point in the history
  • Loading branch information
groverlynn committed Oct 17, 2023
1 parent 969a901 commit 4bddc4f
Show file tree
Hide file tree
Showing 10 changed files with 875 additions and 644 deletions.
2 changes: 1 addition & 1 deletion Squirrel.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@
44AC95181430CF6000C888FB /* SquirrelInputController.h */,
44AC95191430CF6000C888FB /* SquirrelInputController.m */,
A44571AB0DBF42C200F793F9 /* macos_keycode.h */,
32CA4F630368D1EE00C91783 /* Squirrel_Prefix.pch */,
A47C48DE105E8CE8006D528B /* macos_keycode.m */,
32CA4F630368D1EE00C91783 /* Squirrel_Prefix.pch */,
4443A8391828CC5100731305 /* input_source.m */,
29B97316FDCFA39411CA2CEA /* main.m */,
44F84AD514E94C490005D70B /* SquirrelPanel.h */,
Expand Down
2 changes: 2 additions & 0 deletions SquirrelApplicationDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

@class SquirrelConfig;
@class SquirrelPanel;
@class SquirrelOptionSwitcher;

// Note: the SquirrelApplicationDelegate is instantiated automatically as an outlet of NSApp's instance
@interface SquirrelApplicationDelegate : NSObject
Expand All @@ -22,6 +23,7 @@
- (void)startRimeWithFullCheck:(BOOL)fullCheck;
- (void)loadSettings;
- (void)loadSchemaSpecificSettings:(NSString *)schemaId;
- (void)loadSchemaSpecificLabels:(NSString *)schemaId;

@property(nonatomic, readonly) BOOL problematicLaunchDetected;

Expand Down
54 changes: 36 additions & 18 deletions SquirrelApplicationDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ - (IBAction)syncUserData:(id)sender

- (IBAction)configure:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[@"file://" stringByAppendingString:(@"~/Library/Rime").stringByStandardizingPath]]];
[[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[@"~/Library/Rime/" stringByExpandingTildeInPath]]];
}

- (IBAction)openWiki:(id)sender
Expand Down Expand Up @@ -69,13 +69,10 @@ void notification_handler(void *context_object, RimeSessionId session_id,
}
return;
}
// off?
id app_delegate = (__bridge id)context_object;
if (app_delegate && ![app_delegate enableNotifications]) {
return;
}
// schema change
if (!strcmp(message_type, "schema")) {
if (!strcmp(message_type, "schema") &&
app_delegate && [app_delegate enableNotifications]) {
const char *schema_name = strchr(message_value, '/');
if (schema_name) {
++schema_name;
Expand All @@ -84,14 +81,21 @@ void notification_handler(void *context_object, RimeSessionId session_id,
return;
}
// option change
if (!strcmp(message_type, "option")) {
if (!strcmp(message_type, "option") && app_delegate) {
Bool state = message_value[0] != '!';
const char *option_name = message_value + !state;
struct rime_string_slice_t state_label_long = rime_get_api()->get_state_label_abbreviated(session_id, option_name, state, NO);
struct rime_string_slice_t state_label_short = rime_get_api()->get_state_label_abbreviated(session_id, option_name, state, YES);
if (state_label_long.str || state_label_short.str) {
const char *short_message = state_label_short.length < strlen(state_label_short.str) ? NULL : state_label_short.str;
show_status_message(state_label_long.str, short_message, message_type);
if ([[app_delegate panel].optionSwitcher containsOption:@(option_name)]) {
if ([[app_delegate panel].optionSwitcher updateGroupState:@(message_value) ofOption:@(option_name)]) {
[app_delegate loadSchemaSpecificSettings:[app_delegate panel].optionSwitcher.schemaId];
}
}
if ([app_delegate enableNotifications]) {
RimeStringSlice state_label_long = rime_get_api()->get_state_label_abbreviated(session_id, option_name, state, NO);
RimeStringSlice state_label_short = rime_get_api()->get_state_label_abbreviated(session_id, option_name, state, YES);
if (state_label_long.str || state_label_short.str) {
const char *short_message = state_label_short.length < strlen(state_label_short.str) ? NULL : state_label_short.str;
show_status_message(state_label_long.str, short_message, message_type);
}
}
}
}
Expand Down Expand Up @@ -172,26 +176,40 @@ - (void)loadSchemaSpecificSettings:(NSString *)schemaId {
[schema close];
}

- (void)loadSchemaSpecificLabels:(NSString *)schemaId {
if (schemaId.length == 0 || [schemaId characterAtIndex:0] == '.') {
return;
}
SquirrelConfig *defaultConfig = [[SquirrelConfig alloc] init];
[defaultConfig openWithConfigId:@"default"];
SquirrelConfig *schema = [[SquirrelConfig alloc] init];
if ([schema openWithSchemaId:schemaId baseConfig:defaultConfig] &&
[schema hasSection:@"menu"]) {
[self.panel loadLabelConfig:schema];
} else {
[self.panel loadLabelConfig:defaultConfig];
}
[schema close];
[defaultConfig close];
}

// prevent freezing the system
- (BOOL)problematicLaunchDetected
{
BOOL detected = NO;
NSString *logfile =
[NSTemporaryDirectory() stringByAppendingPathComponent:@"squirrel_launch.dat"];
NSString *logfile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"squirrel_launch.dat"];
//NSLog(@"[DEBUG] archive: %@", logfile);
NSData *archive = [NSData dataWithContentsOfFile:logfile
options:NSDataReadingUncached
error:nil];
if (archive) {
NSDate *previousLaunch;
previousLaunch = [NSKeyedUnarchiver unarchivedObjectOfClass:NSDate.class fromData:archive error:NULL];
NSDate *previousLaunch = [NSKeyedUnarchiver unarchivedObjectOfClass:NSDate.class fromData:archive error:NULL];
if (previousLaunch && previousLaunch.timeIntervalSinceNow >= -2) {
detected = YES;
}
}
NSDate *now = [NSDate date];
NSData *record;
record = [NSKeyedArchiver archivedDataWithRootObject:now requiringSecureCoding:NO error:NULL];
NSData *record = [NSKeyedArchiver archivedDataWithRootObject:now requiringSecureCoding:NO error:NULL];
[record writeToFile:logfile atomically:NO];
return detected;
}
Expand Down
30 changes: 29 additions & 1 deletion SquirrelConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,29 @@
typedef NSDictionary<NSString *, NSNumber *> SquirrelAppOptions;
typedef NSMutableDictionary<NSString *, NSNumber *> SquirrelMutableAppOptions;

@interface SquirrelOptionSwitcher : NSObject

@property(nonatomic, strong, readonly) NSString *schemaId;
@property(nonatomic, strong, readonly) NSArray<NSString *> *optionNames;
@property(nonatomic, strong, readonly) NSArray<NSString *> *optionStates;
@property(nonatomic, strong, readonly) NSDictionary<NSString *, NSArray<NSString *> *> *optionGroups;
@property(nonatomic, strong, readonly) NSDictionary<NSString *, NSString *> *switcher;

- (instancetype)initWithSchemaId:(NSString *)schemaId
switcher:(NSDictionary<NSString *, NSString *> *)switcher
optionGroups:(NSDictionary<NSString *, NSArray<NSString *> *> *)optionGroups;

// return whether switcher options has been successfully updated
- (BOOL)updateSwitcher:(NSDictionary<NSString *, NSString *> *)switcher;

- (BOOL)updateGroupState:(NSString *)optionState ofOption:(NSString *)optionName;

- (BOOL)containsOption:(NSString *)optionName;

- (NSMutableDictionary<NSString *, NSString *> *)mutableSwitcher;

@end

@interface SquirrelConfig : NSObject

@property(nonatomic, readonly) BOOL isOpen;
Expand All @@ -12,12 +35,14 @@ typedef NSMutableDictionary<NSString *, NSNumber *> SquirrelMutableAppOptions;
- (BOOL)openBaseConfig;
- (BOOL)openWithSchemaId:(NSString *)schemaId
baseConfig:(SquirrelConfig *)config;
- (BOOL)openUserConfig:(NSString *)configId;
- (BOOL)openWithConfigId:(NSString *)configId;
- (void)close;

- (BOOL)hasSection:(NSString *)section;

- (BOOL)getBool:(NSString *)option;
- (NSInteger)getInt:(NSString *)option;
- (int)getInt:(NSString *)option;
- (double)getDouble:(NSString *)option;
- (NSNumber *)getOptionalBool:(NSString *)option;
- (NSNumber *)getOptionalInt:(NSString *)option;
Expand All @@ -29,6 +54,9 @@ typedef NSMutableDictionary<NSString *, NSNumber *> SquirrelMutableAppOptions;
// file path (absolute or relative to ~/Library/Rime)
- (NSColor *)getPattern:(NSString *)option;

- (NSArray<NSString *> *)getList:(NSString *)option;

- (SquirrelOptionSwitcher *)getOptionSwitcher;
- (SquirrelAppOptions *)getAppOptions:(NSString *)appName;

@end
141 changes: 139 additions & 2 deletions SquirrelConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,81 @@

#import <rime_api.h>

@implementation SquirrelOptionSwitcher {
NSString *_schemaId;
NSDictionary<NSString *, NSString *> *_switcher;
NSDictionary<NSString *, NSArray<NSString *> *> *_optionGroups;
NSArray<NSString *> *_optionNames;
}

- (instancetype)initWithSchemaId:(NSString *)schemaId
switcher:(NSDictionary<NSString *, NSString *> *)switcher
optionGroups:(NSDictionary<NSString *, NSArray<NSString *> *> *)optionGroups{
self = [super init];
if (self) {
_schemaId = schemaId;
_switcher = switcher;
_optionGroups = optionGroups;
_optionNames = [switcher allKeys];
}
return self;
}

- (NSString *)schemaId {
return _schemaId;
}

- (NSArray<NSString *> *)optionNames {
return _optionNames;
}

- (NSArray<NSString *> *)optionStates {
return [_switcher allValues];
}

- (NSDictionary<NSString *, NSString *> *)switcher {
return _switcher;
}

- (BOOL)updateSwitcher:(NSDictionary<NSString *, NSString *> *)switcher {
if (switcher.count != _switcher.count) {
return NO;
}
NSMutableDictionary<NSString *, NSString *> *updatedSwitcher =
[[NSMutableDictionary alloc] initWithCapacity:switcher.count];
for (NSString *option in _optionNames) {
if (switcher[option] == nil) {
return NO;
}
updatedSwitcher[option] = switcher[option];
}
_switcher = [updatedSwitcher copy];
return YES;
}

- (BOOL)updateGroupState:(NSString *)optionState ofOption:(NSString *)optionName {
NSArray<NSString *> *optionGroup = _optionGroups[optionName];
if (!optionGroup || ![optionGroup containsObject:optionState]) {
return NO;
}
NSMutableDictionary<NSString *, NSString *> *updatedSwitcher = [_switcher mutableCopy];
for (NSString *option in optionGroup) {
updatedSwitcher[option] = optionState;
}
_switcher = [updatedSwitcher copy];
return YES;
}

- (BOOL)containsOption:(NSString *)optionName {
return [_optionNames containsObject:optionName];
}

- (NSMutableDictionary<NSString *, NSString *> *)mutableSwitcher {
return [_switcher mutableCopy];
}

@end

@implementation SquirrelConfig {
NSMutableDictionary *_cache;
RimeConfig _config;
Expand Down Expand Up @@ -44,6 +119,18 @@ - (BOOL)openWithSchemaId:(NSString *)schemaId
return _isOpen;
}

- (BOOL)openUserConfig:(NSString *)configId {
[self close];
_isOpen = !!rime_get_api()->user_config_open(configId.UTF8String, &_config);
return _isOpen;
}

- (BOOL)openWithConfigId:(NSString *)configId {
[self close];
_isOpen = !!rime_get_api()->config_open(configId.UTF8String, &_config);
return _isOpen;
}

- (void)close {
if (_isOpen) {
rime_get_api()->config_close(&_config);
Expand All @@ -67,8 +154,8 @@ - (BOOL)getBool:(NSString *)option {
return [self getOptionalBool:option].boolValue;
}

- (NSInteger)getInt:(NSString *)option {
return [self getOptionalInt:option].integerValue;
- (int)getInt:(NSString *)option {
return [self getOptionalInt:option].intValue;
}

- (double)getDouble:(NSString *)option {
Expand Down Expand Up @@ -150,6 +237,56 @@ - (NSColor *)getPattern:(NSString *)option {
return [_baseConfig getPattern:option];
}

- (NSArray<NSString *> *)getList:(NSString *)option {
NSMutableArray<NSString *> *strList = [[NSMutableArray alloc] init];
RimeConfigIterator iterator;
rime_get_api()->config_begin_list(&iterator, &_config, option.UTF8String);
while (rime_get_api()->config_next(&iterator)) {
[strList addObject:[self getString:@(iterator.path)]];
}
rime_get_api()->config_end(&iterator);
return strList;
}

- (SquirrelOptionSwitcher *)getOptionSwitcher {
NSMutableDictionary<NSString *, NSString*> *switcher = [[NSMutableDictionary alloc] init];
NSMutableDictionary<NSString *, NSArray<NSString *> *> *optionGroups = [[NSMutableDictionary alloc] init];
RimeConfigIterator switchIter;
rime_get_api()->config_begin_list(&switchIter, &_config, "switches");
while (rime_get_api()->config_next(&switchIter)) {
int reset = [self getInt:[@(switchIter.path) stringByAppendingString:@"/reset"]];
NSString *name = [self getString:[@(switchIter.path) stringByAppendingString:@"/name"]];
if (name) {
if ([self hasSection:[@"style/!" stringByAppendingString:name]] ||
[self hasSection:[@"style/" stringByAppendingString:name]]) {
switcher[name] = reset ? name : [@"!" stringByAppendingString:name];
optionGroups[name] = @[name];
}
} else {
NSMutableArray *optionGroup = [[NSMutableArray alloc] init];
BOOL hasStyleSection = NO;
RimeConfigIterator optionIter;
rime_get_api()->config_begin_list(&optionIter, &_config, [@(switchIter.path) stringByAppendingString:@"/options"].UTF8String);
while (rime_get_api()->config_next(&optionIter)) {
NSString *option = [self getString:@(optionIter.path)];
[optionGroup addObject:option];
hasStyleSection |= [self hasSection:[@"style/" stringByAppendingString:option]];
}
rime_get_api()->config_end(&optionIter);
if (hasStyleSection) {
for (NSUInteger i = 0; i < optionGroup.count; ++i) {
switcher[optionGroup[i]] = optionGroup[reset];
optionGroups[optionGroup[i]] = optionGroup;
}
}
}
}
rime_get_api()->config_end(&switchIter);
return [[SquirrelOptionSwitcher alloc] initWithSchemaId:_schemaId
switcher:switcher
optionGroups:optionGroups];
}

- (SquirrelAppOptions *)getAppOptions:(NSString *)appName {
NSString *rootKey = [@"app_options/" stringByAppendingString:appName];
SquirrelMutableAppOptions *appOptions = [[SquirrelMutableAppOptions alloc] init];
Expand Down
2 changes: 2 additions & 0 deletions SquirrelInputController.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#import <InputMethodKit/InputMethodKit.h>

@interface SquirrelInputController : IMKInputController

- (BOOL)perform:(NSUInteger)action onIndex:(NSUInteger)index;

@end

#define kSELECT 0x1
Expand Down
Loading

0 comments on commit 4bddc4f

Please sign in to comment.