Skip to content

Instantly share code, notes, and snippets.

@ioquatix
Last active October 12, 2016 21:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ioquatix/f8357f895fbefe4ad96a9e71e668dbf3 to your computer and use it in GitHub Desktop.
Save ioquatix/f8357f895fbefe4ad96a9e71e668dbf3 to your computer and use it in GitHub Desktop.
//
// TTExpressionEditorView.m
// Truth Tables
//
// Created by Samuel Williams on 18/11/11.
// Copyright (c) 2011 Orion Transfer Ltd. All rights reserved.
//
#import "TTExpressionEditorView.h"
#import "NSObject+BindingPropagation.h"
#import "TTParser.h"
#import "TTOperators.h"
enum {
TTEnterKey = 36
};
@implementation TTExpressionEditorView
@synthesize operators = _operators, parser = _parser, expression = _expression;
- (void)awakeFromNib
{
[self setOperators:[TTOperators standardOperators]];
}
- (void) updateExpressionValue:(NSString*)expression into:(NSMutableAttributedString*)buffer
{
// For some reason, when using this font, the vertical alignment becomes odd.
NSFont * identifierFont = [[NSFontManager sharedFontManager] convertFont:self.font toHaveTrait:NSBoldFontMask];
//NSFont * identifierFont = self.font;
NSColor * operatorColor = [NSColor colorWithCalibratedHue:49.0 saturation:0.8 brightness:0.5 alpha:1.0];
if (expression.length > 0) {
TTParser * parser = [TTParser parse:expression withOperators:self.operators];
[self setParser:parser];
{
[buffer addAttribute:NSFontAttributeName value:self.font range:(NSRange){0, buffer.length}];
[buffer removeAttribute:NSForegroundColorAttributeName range:(NSRange){0, buffer.length}];
for (TTToken * token in self.parser.expressions) {
NSRange textRange = {token.offset, token.text.length};
if ([token isKindOfClass:[TTIdentifierToken class]]) {
[buffer addAttribute:NSFontAttributeName value:identifierFont range:textRange];
}
if ([token isKindOfClass:[TTOperatorToken class]]) {
[buffer addAttribute:NSForegroundColorAttributeName value:operatorColor range:textRange];
}
}
for (TTParserError * error in self.parser.errors) {
TTToken * token = error.token;
NSRange textRange = {token.offset, token.text.length};
//NSLog(@"Error at range: %@, %@", NSStringFromRange(textRange), error.message);
if (textRange.location >= buffer.length || (textRange.location + textRange.length) > buffer.length) {
//NSLog(@"Error out of range: %lu", buffer.length);
continue;
}
[buffer addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:textRange];
}
}
} else {
[self setParser:nil];
}
}
- (void) updateEditorHighlighting: (NSString*)expression
{
NSTextView * editor = (NSTextView*)[self currentEditor];
[self updateExpressionValue:self.stringValue into:editor.textStorage];
}
- (void) setExpression:(NSString *)expression
{
if (self.expression == expression)
return;
if (expression && [self.expression isEqualToString:expression])
return;
[self willChangeValueForKey:@"expression"];
_expression = expression;
if (_expression) {
[self setStringValue:_expression];
NSMutableAttributedString * buffer = self.attributedStringValue.mutableCopy;
[self updateExpressionValue:_expression into:buffer];
[self setAllowsEditingTextAttributes:YES];
[self setAttributedStringValue:buffer];
[self setAllowsEditingTextAttributes:NO];
}
//NSLog(@"Editor updated expression: %@", _expression);
[self didChangeValueForKey:@"expression"];
}
- (BOOL)becomeFirstResponder
{
BOOL result = [super becomeFirstResponder];
[self updateEditorHighlighting:self.stringValue];
return result;
}
- (void)textDidChange:(NSNotification *)aNotification
{
[self updateEditorHighlighting:self.stringValue];
[super textDidChange:aNotification];
}
- (void)textDidEndEditing:(NSNotification *)notification
{
if (self.parser && self.parser.errors.count == 0) {
if (![self.stringValue isEqualToString:self.expression]) {
// Update the model
[self setExpression:self.stringValue];
// Seems a bit weird...?
[self propagateValue:self.stringValue forBinding:@"expression"];
}
}
// This causes some issues for selection.
//[super textDidEndEditing:notification];
}
- (BOOL)textShouldEndEditing:(NSText *)textObject
{
NSEvent * event = [NSApp currentEvent];
// The user pressed enter.
if (event.type == NSKeyDown && event.keyCode == TTEnterKey) {
if (self.parser.errors.count != 0) {
return NO;
}
}
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment