├── .gitignore ├── CHANGELOG.md ├── CRYTextViewKit ├── CYRLayoutManager.h ├── CYRLayoutManager.m ├── CYRTextStorage.h ├── CYRTextStorage.m ├── CYRTextView.h ├── CYRTextView.m ├── CYRTextViewKit.h ├── CYRToken.h ├── CYRToken.m └── Info.plist ├── CYRTextView.podspec ├── Example ├── CYRTextViewExample.xcodeproj │ └── project.pbxproj ├── CYRTextViewExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── CYRTextViewExample-Info.plist │ ├── CYRTextViewExample-Prefix.pch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Launch Screen.storyboard │ ├── QEDTextView.h │ ├── QEDTextView.m │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── CYRTextViewExampleTests │ ├── CYRTextViewExampleTests-Info.plist │ ├── CYRTextViewExampleTests.m │ └── en.lproj │ │ └── InfoPlist.strings └── CYRTextViewKitTests │ ├── CYRTextViewTests.swift │ └── Info.plist ├── LICENSE ├── README.md └── Screenshots └── 1.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods 22 | *.xcworkspacedata 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #CYRTextView Changelog 2 | 3 | ##0.4.0 (Sunday, May 25th, 2014) 4 | * Made selected line color a property (Marshall Huss) 5 | * Added defaultTextColor a property on the CYRTextStorage (Marshall Huss) 6 | * Fixed bug whens setting text attributes (Marshall Huss) 7 | 8 | ##0.3.5 (Monday, February 17th, 2014) 9 | * Remove selectedRange KVO on dealloc. (Sam Rijs) 10 | * Update gutter line cursor on selectedRange change. (Sam Rijs) 11 | * Disable auto-correction (Sam Rijs) 12 | * Configurable gutter colors (Sam Rijs) 13 | * Added Hauser and Rijs copyright 14 | 15 | ##0.3.0 (Sunday, January 19th, 2014) 16 | * Bug fixes 17 | * Refactored how the line cursor view is displayed 18 | * Cleanup 19 | 20 | ##0.2.0 (Sunday, January 5th, 2014) 21 | * Initial release with support for regex based syntax highlighting, line numbers, gesture based navigation. 22 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRLayoutManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYRLayoutManager.h 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers 14 | // 15 | // The MIT License (MIT) 16 | // 17 | // Copyright (c) 2014 Cyrillian, Inc. 18 | // 19 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 20 | // this software and associated documentation files (the "Software"), to deal in 21 | // the Software without restriction, including without limitation the rights to 22 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 23 | // the Software, and to permit persons to whom the Software is furnished to do so, 24 | // subject to the following conditions: 25 | // 26 | // The above copyright notice and this permission notice shall be included in all 27 | // copies or substantial portions of the Software. 28 | // 29 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 31 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 32 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 33 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 | 36 | #import 37 | 38 | @interface CYRLayoutManager : NSLayoutManager 39 | 40 | @property (nonatomic, strong) UIFont *lineNumberFont; 41 | @property (nonatomic, strong) UIColor *lineNumberColor; 42 | @property (nonatomic, strong) UIColor *selectedLineNumberColor; 43 | 44 | @property (nonatomic, readonly) CGFloat gutterWidth; 45 | @property (nonatomic, assign) NSRange selectedRange; 46 | 47 | - (CGRect)paragraphRectForRange:(NSRange)range; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRLayoutManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYRLayoutManager.h 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // Original implementation taken from: https://github.com/alldritt/TextKit_LineNumbers 14 | // 15 | // The MIT License (MIT) 16 | // 17 | // Copyright (c) 2014 Cyrillian, Inc. 18 | // 19 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 20 | // this software and associated documentation files (the "Software"), to deal in 21 | // the Software without restriction, including without limitation the rights to 22 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 23 | // the Software, and to permit persons to whom the Software is furnished to do so, 24 | // subject to the following conditions: 25 | // 26 | // The above copyright notice and this permission notice shall be included in all 27 | // copies or substantial portions of the Software. 28 | // 29 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 31 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 32 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 33 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 | 36 | #import "CYRLayoutManager.h" 37 | 38 | static CGFloat kMinimumGutterWidth = 30.f; 39 | 40 | @interface CYRLayoutManager () 41 | 42 | @property (nonatomic, assign) CGFloat gutterWidth; 43 | @property (nonatomic, assign) UIEdgeInsets lineAreaInset; 44 | 45 | @property (nonatomic) NSUInteger lastParaLocation; 46 | @property (nonatomic) NSUInteger lastParaNumber; 47 | 48 | @end 49 | 50 | @implementation CYRLayoutManager 51 | 52 | #pragma mark - Initialization & Setup 53 | 54 | - (instancetype)init 55 | { 56 | self = [super init]; 57 | 58 | if (self) 59 | { 60 | [self _commonSetup]; 61 | } 62 | 63 | return self; 64 | } 65 | 66 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 67 | { 68 | self = [super initWithCoder:aDecoder]; 69 | 70 | if (self) 71 | { 72 | [self _commonSetup]; 73 | } 74 | 75 | return self; 76 | } 77 | 78 | - (void)_commonSetup 79 | { 80 | self.gutterWidth = kMinimumGutterWidth; 81 | self.selectedRange = NSMakeRange(0, 0); 82 | 83 | self.lineAreaInset = UIEdgeInsetsMake(0, 10, 0, 4); 84 | self.lineNumberColor = [UIColor grayColor]; 85 | self.lineNumberFont = [UIFont systemFontOfSize:10.0f]; 86 | self.selectedLineNumberColor = [UIColor colorWithWhite:0.9 alpha:1]; 87 | } 88 | 89 | 90 | #pragma mark - Convenience 91 | 92 | - (CGRect)paragraphRectForRange:(NSRange)range 93 | { 94 | range = [self.textStorage.string paragraphRangeForRange:range]; 95 | range = [self glyphRangeForCharacterRange:range actualCharacterRange:NULL]; 96 | 97 | CGRect startRect = [self lineFragmentRectForGlyphAtIndex:range.location effectiveRange:NULL]; 98 | CGRect endRect = [self lineFragmentRectForGlyphAtIndex:range.location + range.length - 1 effectiveRange:NULL]; 99 | 100 | CGRect paragraphRectForRange = CGRectUnion(startRect, endRect); 101 | paragraphRectForRange = CGRectOffset(paragraphRectForRange, _gutterWidth, 8); 102 | 103 | return paragraphRectForRange; 104 | } 105 | 106 | - (NSUInteger) _paraNumberForRange:(NSRange) charRange 107 | { 108 | // NSString does not provide a means of efficiently determining the paragraph number of a range of text. This code 109 | // attempts to optimize what would normally be a series linear searches by keeping track of the last paragraph number 110 | // found and uses that as the starting point for next paragraph number search. This works (mostly) because we 111 | // are generally asked for continguous increasing sequences of paragraph numbers. Also, this code is called in the 112 | // course of drawing a pagefull of text, and so even when moving back, the number of paragraphs to search for is 113 | // relativly low, even in really long bodies of text. 114 | // 115 | // This all falls down when the user edits the text, and can potentially invalidate the cached paragraph number which 116 | // causes a (potentially lengthy) search from the beginning of the string. 117 | 118 | if (charRange.location == self.lastParaLocation) 119 | return self.lastParaNumber; 120 | else if (charRange.location < self.lastParaLocation) 121 | { 122 | // We need to look backwards from the last known paragraph for the new paragraph range. This generally happens 123 | // when the text in the UITextView scrolls downward, revaling paragraphs before/above the ones previously drawn. 124 | 125 | NSString* s = self.textStorage.string; 126 | __block NSUInteger paraNumber = self.lastParaNumber; 127 | 128 | [s enumerateSubstringsInRange:NSMakeRange(charRange.location, self.lastParaLocation - charRange.location) 129 | options:NSStringEnumerationByParagraphs | 130 | NSStringEnumerationSubstringNotRequired | 131 | NSStringEnumerationReverse 132 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){ 133 | if (enclosingRange.location <= charRange.location) { 134 | *stop = YES; 135 | } 136 | --paraNumber; 137 | }]; 138 | 139 | self.lastParaLocation = charRange.location; 140 | self.lastParaNumber = paraNumber; 141 | 142 | return paraNumber; 143 | } 144 | else 145 | { 146 | // We need to look forward from the last known paragraph for the new paragraph range. This generally happens 147 | // when the text in the UITextView scrolls upwards, revealing paragraphs that follow the ones previously drawn. 148 | 149 | NSString* s = self.textStorage.string; 150 | __block NSUInteger paraNumber = self.lastParaNumber; 151 | 152 | [s enumerateSubstringsInRange:NSMakeRange(self.lastParaLocation, charRange.location - self.lastParaLocation) 153 | options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired 154 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){ 155 | if (enclosingRange.location >= charRange.location) { 156 | *stop = YES; 157 | } 158 | ++paraNumber; 159 | }]; 160 | 161 | self.lastParaLocation = charRange.location; 162 | self.lastParaNumber = paraNumber; 163 | 164 | return paraNumber; 165 | } 166 | } 167 | 168 | 169 | #pragma mark - Layouting 170 | 171 | - (void)processEditingForTextStorage:(NSTextStorage *)textStorage edited:(NSTextStorageEditActions)editMask range:(NSRange)newCharRange changeInLength:(NSInteger)delta invalidatedRange:(NSRange)invalidatedCharRange 172 | { 173 | [super processEditingForTextStorage:textStorage edited:editMask range:newCharRange changeInLength:delta invalidatedRange:invalidatedCharRange]; 174 | 175 | if (invalidatedCharRange.location < self.lastParaLocation) 176 | { 177 | // When the backing store is edited ahead the cached paragraph location, invalidate the cache and force a complete 178 | // recalculation. We cannot be much smarter than this because we don't know how many paragraphs have been deleted 179 | // since the text has already been removed from the backing store. 180 | self.lastParaLocation = 0; 181 | self.lastParaNumber = 0; 182 | } 183 | } 184 | 185 | 186 | #pragma mark - Drawing 187 | 188 | - (void) drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin 189 | { 190 | [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin]; 191 | 192 | // Draw line numbers. Note that the background for line number gutter is drawn by the LineNumberTextView class. 193 | NSDictionary* atts = @{NSFontAttributeName : _lineNumberFont , 194 | NSForegroundColorAttributeName : _lineNumberColor}; 195 | 196 | [self enumerateLineFragmentsForGlyphRange:glyphsToShow 197 | usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) { 198 | NSRange charRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:nil]; 199 | NSRange paraRange = [self.textStorage.string paragraphRangeForRange:charRange]; 200 | 201 | BOOL showCursorRect = NSLocationInRange(_selectedRange.location, paraRange); 202 | 203 | if (showCursorRect) 204 | { 205 | CGContextRef context = UIGraphicsGetCurrentContext(); 206 | CGRect cursorRect = CGRectMake(0, usedRect.origin.y + 8, _gutterWidth, usedRect.size.height); 207 | 208 | CGContextSetFillColorWithColor(context, _selectedLineNumberColor.CGColor); 209 | CGContextFillRect(context, cursorRect); 210 | } 211 | 212 | // Only draw line numbers for the paragraph's first line fragment. Subsequent fragments are wrapped portions of the paragraph and don't get the line number. 213 | if (charRange.location == paraRange.location) { 214 | CGRect gutterRect = CGRectOffset(CGRectMake(0, rect.origin.y, _gutterWidth, rect.size.height), origin.x, origin.y); 215 | NSUInteger paraNumber = [self _paraNumberForRange:charRange]; 216 | NSString* ln = [NSString stringWithFormat:@"%ld", (unsigned long) paraNumber + 1]; 217 | CGSize size = [ln sizeWithAttributes:atts]; 218 | 219 | [ln drawInRect:CGRectOffset(gutterRect, CGRectGetWidth(gutterRect) - _lineAreaInset.right - size.width - _gutterWidth, (CGRectGetHeight(gutterRect) - size.height) / 2.0) 220 | withAttributes:atts]; 221 | } 222 | 223 | }]; 224 | } 225 | 226 | @end 227 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRTextStorage.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextStorage.h 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // 14 | // The MIT License (MIT) 15 | // 16 | // Copyright (c) 2014 Cyrillian, Inc. 17 | // 18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | // this software and associated documentation files (the "Software"), to deal in 20 | // the Software without restriction, including without limitation the rights to 21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 22 | // the Software, and to permit persons to whom the Software is furnished to do so, 23 | // subject to the following conditions: 24 | // 25 | // The above copyright notice and this permission notice shall be included in all 26 | // copies or substantial portions of the Software. 27 | // 28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | #import 36 | 37 | @class CYRToken; 38 | 39 | @interface CYRTextStorage : NSTextStorage 40 | 41 | @property (nonatomic, strong) NSArray *tokens; 42 | @property (nonatomic, strong) UIFont *defaultFont; 43 | @property (nonatomic, strong) UIColor *defaultTextColor; 44 | 45 | - (void)update; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRTextStorage.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextStorage.m 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // 14 | // The MIT License (MIT) 15 | // 16 | // Copyright (c) 2014 Cyrillian, Inc. 17 | // 18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | // this software and associated documentation files (the "Software"), to deal in 20 | // the Software without restriction, including without limitation the rights to 21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 22 | // the Software, and to permit persons to whom the Software is furnished to do so, 23 | // subject to the following conditions: 24 | // 25 | // The above copyright notice and this permission notice shall be included in all 26 | // copies or substantial portions of the Software. 27 | // 28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | #import "CYRTextStorage.h" 36 | #import "CYRToken.h" 37 | 38 | @interface CYRTextStorage () 39 | 40 | @property (nonatomic, strong) NSMutableAttributedString *attributedString; 41 | @property (nonatomic, strong) NSMutableDictionary *regularExpressionCache; 42 | 43 | @end 44 | 45 | @implementation CYRTextStorage 46 | 47 | #pragma mark - Initialization & Setup 48 | 49 | - (id)init 50 | { 51 | if (self = [super init]) 52 | { 53 | _defaultFont = [UIFont systemFontOfSize:12.0f]; 54 | _defaultTextColor = [UIColor blackColor]; 55 | _attributedString = [NSMutableAttributedString new]; 56 | 57 | _tokens = @[]; 58 | _regularExpressionCache = @{}.mutableCopy; 59 | } 60 | 61 | return self; 62 | } 63 | 64 | 65 | #pragma mark - Overrides 66 | 67 | - (void)setTokens:(NSMutableArray *)tokens 68 | { 69 | _tokens = tokens; 70 | 71 | // Clear the regular expression cache 72 | [self.regularExpressionCache removeAllObjects]; 73 | 74 | // Redraw all text 75 | [self update]; 76 | } 77 | 78 | - (NSString *)string 79 | { 80 | return [_attributedString string]; 81 | } 82 | 83 | - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range 84 | { 85 | return [_attributedString attributesAtIndex:location effectiveRange:range]; 86 | } 87 | 88 | - (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)str 89 | { 90 | [self beginEditing]; 91 | 92 | [_attributedString replaceCharactersInRange:range withString:str]; 93 | 94 | [self edited:NSTextStorageEditedCharacters | NSTextStorageEditedAttributes range:range changeInLength:str.length - range.length]; 95 | [self endEditing]; 96 | } 97 | 98 | - (void)setAttributes:(NSDictionary*)attrs range:(NSRange)range 99 | { 100 | [self beginEditing]; 101 | 102 | [_attributedString setAttributes:attrs range:range]; 103 | 104 | [self edited:NSTextStorageEditedAttributes range:range changeInLength:0]; 105 | [self endEditing]; 106 | } 107 | 108 | -(void)processEditing 109 | { 110 | [self performReplacementsForRange:[self editedRange]]; 111 | [super processEditing]; 112 | } 113 | 114 | - (void)performReplacementsForRange:(NSRange)changedRange 115 | { 116 | NSRange extendedRange = NSUnionRange(changedRange, [[_attributedString string] lineRangeForRange:NSMakeRange(NSMaxRange(changedRange), 0)]); 117 | 118 | [self applyStylesToRange:extendedRange]; 119 | } 120 | 121 | 122 | -(void)update 123 | { 124 | NSRange range = NSMakeRange(0, self.length); 125 | 126 | NSDictionary *attributes = 127 | @{ 128 | NSFontAttributeName : self.defaultFont, 129 | NSForegroundColorAttributeName : self.defaultTextColor 130 | }; 131 | [self addAttributes:attributes range:range]; 132 | 133 | [self applyStylesToRange:range]; 134 | } 135 | 136 | - (void)applyStylesToRange:(NSRange)searchRange 137 | { 138 | if (self.editedRange.location == NSNotFound) 139 | { 140 | return; 141 | } 142 | 143 | NSRange paragaphRange = [self.string paragraphRangeForRange: self.editedRange]; 144 | 145 | // Reset the text attributes 146 | NSDictionary *attributes = 147 | @{ 148 | NSFontAttributeName : self.defaultFont, 149 | NSForegroundColorAttributeName : self.defaultTextColor 150 | }; 151 | [self setAttributes:attributes range:paragaphRange]; 152 | 153 | for (CYRToken *attribute in self.tokens) 154 | { 155 | NSRegularExpression *regex = [self expressionForDefinition:attribute.name]; 156 | 157 | [regex enumerateMatchesInString:self.string options:0 range:paragaphRange 158 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 159 | 160 | [attribute.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, id attributeValue, BOOL *stop) { 161 | [self addAttribute:attributeName value:attributeValue range:result.range]; 162 | }]; 163 | }]; 164 | } 165 | } 166 | 167 | - (NSRegularExpression *)expressionForDefinition:(NSString *)definition 168 | { 169 | __block CYRToken *attribute = nil; 170 | 171 | [self.tokens enumerateObjectsUsingBlock:^(CYRToken *enumeratedAttribute, NSUInteger idx, BOOL *stop) { 172 | if ([enumeratedAttribute.name isEqualToString:definition]) 173 | { 174 | attribute = enumeratedAttribute; 175 | *stop = YES; 176 | } 177 | }]; 178 | 179 | NSRegularExpression *expression = self.regularExpressionCache[attribute.expression]; 180 | 181 | if (!expression) 182 | { 183 | expression = [NSRegularExpression regularExpressionWithPattern:attribute.expression 184 | options:NSRegularExpressionCaseInsensitive error:nil]; 185 | 186 | [self.regularExpressionCache setObject:expression forKey:definition]; 187 | } 188 | 189 | return expression; 190 | } 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextView.h 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // Copyright (c) 2013 Dominik Hauser 9 | // Copyright (c) 2013 Sam Rijs 10 | // 11 | // Distributed under MIT license. 12 | // Get the latest version from here: 13 | // 14 | // https://github.com/illyabusigin/CYRTextView 15 | // Gestures sourced from: https://github.com/srijs/NLTextView 16 | // 17 | // The MIT License (MIT) 18 | // 19 | // Copyright (c) 2014 Cyrillian, Inc. 20 | // 21 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 22 | // this software and associated documentation files (the "Software"), to deal in 23 | // the Software without restriction, including without limitation the rights to 24 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 25 | // the Software, and to permit persons to whom the Software is furnished to do so, 26 | // subject to the following conditions: 27 | // 28 | // The above copyright notice and this permission notice shall be included in all 29 | // copies or substantial portions of the Software. 30 | // 31 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 33 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 34 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 35 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 36 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | 38 | #import 39 | #import "CYRToken.h" 40 | 41 | @class CYRToken; 42 | 43 | @interface CYRTextView : UITextView 44 | 45 | @property (nonatomic, strong) NSArray *tokens; 46 | @property (nonatomic, strong) UIPanGestureRecognizer *singleFingerPanRecognizer; 47 | @property (nonatomic, strong) UIPanGestureRecognizer *doubleFingerPanRecognizer; 48 | 49 | @property UIColor *gutterBackgroundColor; 50 | @property UIColor *gutterLineColor; 51 | 52 | @property (nonatomic, assign) BOOL lineCursorEnabled; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextView.m 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // Copyright (c) 2013 Dominik Hauser 9 | // Copyright (c) 2013 Sam Rijs 10 | // 11 | // Distributed under MIT license. 12 | // Get the latest version from here: 13 | // 14 | // https://github.com/illyabusigin/CYRTextView 15 | // 16 | // The MIT License (MIT) 17 | // 18 | // Copyright (c) 2014 Cyrillian, Inc. 19 | // 20 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 21 | // this software and associated documentation files (the "Software"), to deal in 22 | // the Software without restriction, including without limitation the rights to 23 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 24 | // the Software, and to permit persons to whom the Software is furnished to do so, 25 | // subject to the following conditions: 26 | // 27 | // The above copyright notice and this permission notice shall be included in all 28 | // copies or substantial portions of the Software. 29 | // 30 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 32 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 33 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 34 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 35 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | 37 | #import "CYRTextView.h" 38 | #import "CYRLayoutManager.h" 39 | #import "CYRTextStorage.h" 40 | 41 | #define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f] 42 | 43 | static void *CYRTextViewContext = &CYRTextViewContext; 44 | static const float kCursorVelocity = 1.0f/8.0f; 45 | 46 | @interface CYRTextView () 47 | 48 | @property (nonatomic, strong) CYRLayoutManager *lineNumberLayoutManager; 49 | @property (nonatomic, strong) CYRTextStorage *syntaxTextStorage; 50 | 51 | @end 52 | 53 | @implementation CYRTextView 54 | { 55 | NSRange startRange; 56 | } 57 | 58 | #pragma mark - Initialization & Setup 59 | 60 | - (id)initWithFrame:(CGRect)frame 61 | { 62 | CYRTextStorage *textStorage = [CYRTextStorage new]; 63 | CYRLayoutManager *layoutManager = [CYRLayoutManager new]; 64 | 65 | self.lineNumberLayoutManager = layoutManager; 66 | 67 | NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; 68 | 69 | // Wrap text to the text view's frame 70 | textContainer.widthTracksTextView = YES; 71 | 72 | [layoutManager addTextContainer:textContainer]; 73 | 74 | [textStorage removeLayoutManager:textStorage.layoutManagers.firstObject]; 75 | [textStorage addLayoutManager:layoutManager]; 76 | 77 | self.syntaxTextStorage = textStorage; 78 | 79 | if ((self = [super initWithFrame:frame textContainer:textContainer])) 80 | { 81 | self.contentMode = UIViewContentModeRedraw; // causes drawRect: to be called on frame resizing and device rotation 82 | 83 | [self _commonSetup]; 84 | } 85 | 86 | return self; 87 | } 88 | 89 | - (void)_commonSetup 90 | { 91 | // Setup observers 92 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(font)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext]; 93 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(textColor)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext]; 94 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext]; 95 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange)) options:NSKeyValueObservingOptionNew context:CYRTextViewContext]; 96 | 97 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextViewDidChangeNotification:) name:UITextViewTextDidChangeNotification object:self]; 98 | 99 | // Setup defaults 100 | self.font = [UIFont systemFontOfSize:16.0f]; 101 | self.textColor = [UIColor blackColor]; 102 | self.autocapitalizationType = UITextAutocapitalizationTypeNone; 103 | self.autocorrectionType = UITextAutocorrectionTypeNo; 104 | self.lineCursorEnabled = YES; 105 | self.gutterBackgroundColor = [UIColor colorWithWhite:0.95 alpha:1]; 106 | self.gutterLineColor = [UIColor lightGrayColor]; 107 | 108 | // Inset the content to make room for line numbers 109 | self.textContainerInset = UIEdgeInsetsMake(8, self.lineNumberLayoutManager.gutterWidth, 8, 0); 110 | 111 | // Setup the gesture recognizers 112 | _singleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(singleFingerPanHappend:)]; 113 | _singleFingerPanRecognizer.maximumNumberOfTouches = 1; 114 | [self addGestureRecognizer:_singleFingerPanRecognizer]; 115 | 116 | _doubleFingerPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doubleFingerPanHappend:)]; 117 | _doubleFingerPanRecognizer.minimumNumberOfTouches = 2; 118 | [self addGestureRecognizer:_doubleFingerPanRecognizer]; 119 | } 120 | 121 | 122 | #pragma mark - Cleanup 123 | 124 | - (void)dealloc 125 | { 126 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(font))]; 127 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(textColor))]; 128 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedTextRange))]; 129 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedRange))]; 130 | } 131 | 132 | 133 | #pragma mark - KVO 134 | 135 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 136 | { 137 | if ([keyPath isEqualToString:NSStringFromSelector(@selector(font))] && context == CYRTextViewContext) 138 | { 139 | // Whenever the UITextView font is changed we want to keep a reference in the stickyFont ivar. We do this to counteract a bug where the underlying font can be changed without notice and cause undesired behaviour. 140 | self.syntaxTextStorage.defaultFont = self.font; 141 | } 142 | else if ([keyPath isEqualToString:NSStringFromSelector(@selector(textColor))] && context == CYRTextViewContext) 143 | { 144 | self.syntaxTextStorage.defaultTextColor = self.textColor; 145 | } 146 | else if (([keyPath isEqualToString:NSStringFromSelector(@selector(selectedTextRange))] || 147 | [keyPath isEqualToString:NSStringFromSelector(@selector(selectedRange))]) && context == CYRTextViewContext) 148 | { 149 | [self setNeedsDisplay]; 150 | } 151 | else 152 | { 153 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 154 | } 155 | } 156 | 157 | 158 | #pragma mark - Notifications 159 | 160 | - (void)handleTextViewDidChangeNotification:(NSNotification *)notification 161 | { 162 | if (notification.object == self) 163 | { 164 | CGRect line = [self caretRectForPosition: self.selectedTextRange.start]; 165 | CGFloat overflow = line.origin.y + line.size.height - ( self.contentOffset.y + self.bounds.size.height - self.contentInset.bottom - self.contentInset.top ); 166 | 167 | if ( overflow > 0 ) 168 | { 169 | // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it) 170 | // Scroll caret to visible area 171 | CGPoint offset = self.contentOffset; 172 | offset.y += overflow + 7; // leave 7 pixels margin 173 | // Cannot animate with setContentOffset:animated: or caret will not appear 174 | // [UIView animateWithDuration:.2 animations:^{ 175 | // [self setContentOffset:offset]; 176 | // }]; 177 | } 178 | } 179 | } 180 | 181 | 182 | #pragma mark - Overrides 183 | 184 | - (void)setTokens:(NSMutableArray *)tokens 185 | { 186 | [self.syntaxTextStorage setTokens:tokens]; 187 | } 188 | 189 | - (NSArray *)tokens 190 | { 191 | CYRTextStorage *syntaxTextStorage = (CYRTextStorage *)self.textStorage; 192 | 193 | return syntaxTextStorage.tokens; 194 | } 195 | 196 | - (void)setText:(NSString *)text 197 | { 198 | UITextRange *textRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument]; 199 | [self replaceRange:textRange withText:text]; 200 | } 201 | 202 | 203 | #pragma mark - Line Drawing 204 | 205 | // Original implementation sourced from: https://github.com/alldritt/TextKit_LineNumbers 206 | - (void)drawRect:(CGRect)rect 207 | { 208 | // Drag the line number gutter background. The line numbers them selves are drawn by LineNumberLayoutManager. 209 | CGContextRef context = UIGraphicsGetCurrentContext(); 210 | CGRect bounds = self.bounds; 211 | 212 | CGFloat height = MAX(CGRectGetHeight(bounds), self.contentSize.height) + 200; 213 | 214 | // Set the regular fill 215 | CGContextSetFillColorWithColor(context, self.gutterBackgroundColor.CGColor); 216 | CGContextFillRect(context, CGRectMake(bounds.origin.x, bounds.origin.y, self.lineNumberLayoutManager.gutterWidth, height)); 217 | 218 | // Draw line 219 | CGContextSetFillColorWithColor(context, self.gutterLineColor.CGColor); 220 | CGContextFillRect(context, CGRectMake(self.lineNumberLayoutManager.gutterWidth, bounds.origin.y, 0.5, height)); 221 | 222 | if (_lineCursorEnabled) 223 | { 224 | self.lineNumberLayoutManager.selectedRange = self.selectedRange; 225 | 226 | NSRange glyphRange = [self.lineNumberLayoutManager.textStorage.string paragraphRangeForRange:self.selectedRange]; 227 | glyphRange = [self.lineNumberLayoutManager glyphRangeForCharacterRange:glyphRange actualCharacterRange:NULL]; 228 | self.lineNumberLayoutManager.selectedRange = glyphRange; 229 | [self.lineNumberLayoutManager invalidateDisplayForGlyphRange:glyphRange]; 230 | } 231 | 232 | [super drawRect:rect]; 233 | } 234 | 235 | 236 | #pragma mark - Gestures 237 | 238 | // Sourced from: https://github.com/srijs/NLTextView 239 | - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer 240 | { 241 | // Only accept horizontal pans for the code navigation to preserve correct scrolling behaviour. 242 | if (gestureRecognizer == _singleFingerPanRecognizer || gestureRecognizer == _doubleFingerPanRecognizer) 243 | { 244 | CGPoint translation = [gestureRecognizer translationInView:self]; 245 | return fabs(translation.x) > fabs(translation.y); 246 | } 247 | 248 | return YES; 249 | 250 | } 251 | 252 | // Sourced from: https://github.com/srijs/NLTextView 253 | - (void)singleFingerPanHappend:(UIPanGestureRecognizer *)sender 254 | { 255 | if (sender.state == UIGestureRecognizerStateBegan) 256 | { 257 | startRange = self.selectedRange; 258 | } 259 | 260 | CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0); 261 | 262 | self.selectedRange = NSMakeRange(cursorLocation, 0); 263 | } 264 | 265 | // Sourced from: https://github.com/srijs/NLTextView 266 | - (void)doubleFingerPanHappend:(UIPanGestureRecognizer *)sender 267 | { 268 | if (sender.state == UIGestureRecognizerStateBegan) 269 | { 270 | startRange = self.selectedRange; 271 | } 272 | 273 | CGFloat cursorLocation = MAX(startRange.location + [sender translationInView:self].x * kCursorVelocity, 0); 274 | 275 | if (cursorLocation > startRange.location) 276 | { 277 | self.selectedRange = NSMakeRange(startRange.location, fabs(startRange.location - cursorLocation)); 278 | } 279 | else 280 | { 281 | self.selectedRange = NSMakeRange(cursorLocation, fabs(startRange.location - cursorLocation)); 282 | } 283 | } 284 | 285 | @end 286 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRTextViewKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextViewKit.h 3 | // CYRTextView 4 | // 5 | // Created by Dustin Pfannenstiel on 1/11/16. 6 | // Copyright © 2016 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CYRTextView. 12 | FOUNDATION_EXPORT double CYRTextViewKitVersionNumber; 13 | 14 | //! Project version string for CYRTextView. 15 | FOUNDATION_EXPORT const unsigned char CYRTextViewKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | #import 19 | #import 20 | 21 | 22 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextAttribute.h 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // 14 | // The MIT License (MIT) 15 | // 16 | // Copyright (c) 2014 Cyrillian, Inc. 17 | // 18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | // this software and associated documentation files (the "Software"), to deal in 20 | // the Software without restriction, including without limitation the rights to 21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 22 | // the Software, and to permit persons to whom the Software is furnished to do so, 23 | // subject to the following conditions: 24 | // 25 | // The above copyright notice and this permission notice shall be included in all 26 | // copies or substantial portions of the Software. 27 | // 28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | #import 36 | 37 | @interface CYRToken : NSObject 38 | 39 | @property (nonatomic, strong, nullable) NSString *name; 40 | @property (nonatomic, strong, nullable) NSString *expression; 41 | @property (nonatomic, strong, nullable) NSDictionary *attributes; 42 | 43 | + (nonnull instancetype)tokenWithName:(nullable NSString *)name expression:(nullable NSString *)expression attributes:(nullable NSDictionary *)attributes; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CRYTextViewKit/CYRToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextAttribute.m 3 | // 4 | // Version 0.4.0 5 | // 6 | // Created by Illya Busigin on 01/05/2014. 7 | // Copyright (c) 2014 Cyrillian, Inc. 8 | // 9 | // Distributed under MIT license. 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/illyabusigin/CYRTextView 13 | // 14 | // The MIT License (MIT) 15 | // 16 | // Copyright (c) 2014 Cyrillian, Inc. 17 | // 18 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | // this software and associated documentation files (the "Software"), to deal in 20 | // the Software without restriction, including without limitation the rights to 21 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 22 | // the Software, and to permit persons to whom the Software is furnished to do so, 23 | // subject to the following conditions: 24 | // 25 | // The above copyright notice and this permission notice shall be included in all 26 | // copies or substantial portions of the Software. 27 | // 28 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 30 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 31 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 32 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | 35 | #import "CYRToken.h" 36 | 37 | @implementation CYRToken 38 | 39 | + (instancetype)tokenWithName:(NSString *)name expression:(NSString *)expression attributes:(NSDictionary *)attributes 40 | { 41 | CYRToken *textAttribute = [CYRToken new]; 42 | 43 | textAttribute.name = name; 44 | textAttribute.expression = expression; 45 | textAttribute.attributes = attributes; 46 | 47 | return textAttribute; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /CRYTextViewKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /CYRTextView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'CYRTextView' 3 | s.version = '0.4.1' 4 | s.license = { :type => 'MIT', :file => 'LICENSE' } 5 | s.summary = 'A rich text view that allows easy syntax highlighting through regular expressions, line numbers, and more.' 6 | s.author = { 'Illya Busigin' => 'http://illyabusigin.com/' } 7 | s.source = { :git => 'https://github.com/illyabusigin/CYRTextView.git', :tag => '0.4.0' } 8 | s.homepage = 'https://github.com/illyabusigin/CYRTextView' 9 | s.platform = :ios 10 | s.source_files = 'CYRTextViewKit' 11 | s.frameworks = 'CoreText' 12 | s.requires_arc = true 13 | s.ios.deployment_target = '9.0' 14 | end 15 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 393953D7187A18F300A19DEC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953D6187A18F300A19DEC /* Foundation.framework */; }; 11 | 393953D9187A18F300A19DEC /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953D8187A18F300A19DEC /* CoreGraphics.framework */; }; 12 | 393953DB187A18F300A19DEC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953DA187A18F300A19DEC /* UIKit.framework */; }; 13 | 393953E1187A18F300A19DEC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 393953DF187A18F300A19DEC /* InfoPlist.strings */; }; 14 | 393953E3187A18F300A19DEC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 393953E2187A18F300A19DEC /* main.m */; }; 15 | 393953E7187A18F300A19DEC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 393953E6187A18F300A19DEC /* AppDelegate.m */; }; 16 | 393953F0187A18F300A19DEC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 393953EF187A18F300A19DEC /* ViewController.m */; }; 17 | 393953F2187A18F300A19DEC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 393953F1187A18F300A19DEC /* Images.xcassets */; }; 18 | 393953F9187A18F300A19DEC /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953F8187A18F300A19DEC /* XCTest.framework */; }; 19 | 393953FA187A18F300A19DEC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953D6187A18F300A19DEC /* Foundation.framework */; }; 20 | 393953FB187A18F300A19DEC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 393953DA187A18F300A19DEC /* UIKit.framework */; }; 21 | 39395403187A18F300A19DEC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 39395401187A18F300A19DEC /* InfoPlist.strings */; }; 22 | 39395405187A18F300A19DEC /* CYRTextViewExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 39395404187A18F300A19DEC /* CYRTextViewExampleTests.m */; }; 23 | 3939540F187A193100A19DEC /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3939540E187A193100A19DEC /* CoreText.framework */; }; 24 | 39BE428A1880FDA9002BE6FF /* QEDTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 39BE42891880FDA9002BE6FF /* QEDTextView.m */; }; 25 | DA0C0E701C44214F001EA3FA /* CYRTextViewKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA0C0E6F1C44214F001EA3FA /* CYRTextViewKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | DA0C0E771C44214F001EA3FA /* CYRTextViewKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */; }; 27 | DA0C0E7E1C44214F001EA3FA /* CYRTextViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0C0E7D1C44214F001EA3FA /* CYRTextViewTests.swift */; }; 28 | DA0C0E821C44214F001EA3FA /* CYRTextViewKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */; }; 29 | DA0C0E831C44214F001EA3FA /* CYRTextViewKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 30 | DA0C0E8B1C44215D001EA3FA /* CYRLayoutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 39395411187A6AFE00A19DEC /* CYRLayoutManager.h */; }; 31 | DA0C0E8C1C44215D001EA3FA /* CYRLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 39395412187A6AFE00A19DEC /* CYRLayoutManager.m */; }; 32 | DA0C0E8D1C44215D001EA3FA /* CYRTextStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 39395413187A6AFE00A19DEC /* CYRTextStorage.h */; }; 33 | DA0C0E8E1C44215D001EA3FA /* CYRTextStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 39395414187A6AFE00A19DEC /* CYRTextStorage.m */; }; 34 | DA0C0E8F1C44215D001EA3FA /* CYRTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 39395415187A6AFE00A19DEC /* CYRTextView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 35 | DA0C0E901C44215D001EA3FA /* CYRTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 39395416187A6AFE00A19DEC /* CYRTextView.m */; }; 36 | DA0C0E911C44215D001EA3FA /* CYRToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 39395417187A6AFE00A19DEC /* CYRToken.h */; settings = {ATTRIBUTES = (Public, ); }; }; 37 | DA0C0E921C44215D001EA3FA /* CYRToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 39395418187A6AFE00A19DEC /* CYRToken.m */; }; 38 | DA0C0E941C4437B9001EA3FA /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA0C0E931C4437B9001EA3FA /* Launch Screen.storyboard */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXContainerItemProxy section */ 42 | 393953FC187A18F300A19DEC /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 393953CB187A18F300A19DEC /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 393953D2187A18F300A19DEC; 47 | remoteInfo = CYRTextViewExample; 48 | }; 49 | DA0C0E781C44214F001EA3FA /* PBXContainerItemProxy */ = { 50 | isa = PBXContainerItemProxy; 51 | containerPortal = 393953CB187A18F300A19DEC /* Project object */; 52 | proxyType = 1; 53 | remoteGlobalIDString = DA0C0E6C1C44214F001EA3FA; 54 | remoteInfo = CYRTextView; 55 | }; 56 | DA0C0E7A1C44214F001EA3FA /* PBXContainerItemProxy */ = { 57 | isa = PBXContainerItemProxy; 58 | containerPortal = 393953CB187A18F300A19DEC /* Project object */; 59 | proxyType = 1; 60 | remoteGlobalIDString = 393953D2187A18F300A19DEC; 61 | remoteInfo = CYRTextViewExample; 62 | }; 63 | DA0C0E801C44214F001EA3FA /* PBXContainerItemProxy */ = { 64 | isa = PBXContainerItemProxy; 65 | containerPortal = 393953CB187A18F300A19DEC /* Project object */; 66 | proxyType = 1; 67 | remoteGlobalIDString = DA0C0E6C1C44214F001EA3FA; 68 | remoteInfo = CYRTextView; 69 | }; 70 | /* End PBXContainerItemProxy section */ 71 | 72 | /* Begin PBXCopyFilesBuildPhase section */ 73 | DA0C0E871C44214F001EA3FA /* Embed Frameworks */ = { 74 | isa = PBXCopyFilesBuildPhase; 75 | buildActionMask = 2147483647; 76 | dstPath = ""; 77 | dstSubfolderSpec = 10; 78 | files = ( 79 | DA0C0E831C44214F001EA3FA /* CYRTextViewKit.framework in Embed Frameworks */, 80 | ); 81 | name = "Embed Frameworks"; 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXCopyFilesBuildPhase section */ 85 | 86 | /* Begin PBXFileReference section */ 87 | 393953D3187A18F300A19DEC /* CYRTextViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CYRTextViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | 393953D6187A18F300A19DEC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 89 | 393953D8187A18F300A19DEC /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 90 | 393953DA187A18F300A19DEC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 91 | 393953DE187A18F300A19DEC /* CYRTextViewExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CYRTextViewExample-Info.plist"; sourceTree = ""; }; 92 | 393953E0187A18F300A19DEC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 93 | 393953E2187A18F300A19DEC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 94 | 393953E4187A18F300A19DEC /* CYRTextViewExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CYRTextViewExample-Prefix.pch"; sourceTree = ""; }; 95 | 393953E5187A18F300A19DEC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 96 | 393953E6187A18F300A19DEC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 97 | 393953EE187A18F300A19DEC /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 98 | 393953EF187A18F300A19DEC /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 99 | 393953F1187A18F300A19DEC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 100 | 393953F7187A18F300A19DEC /* CYRTextViewExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CYRTextViewExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 101 | 393953F8187A18F300A19DEC /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 102 | 39395400187A18F300A19DEC /* CYRTextViewExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CYRTextViewExampleTests-Info.plist"; sourceTree = ""; }; 103 | 39395402187A18F300A19DEC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 104 | 39395404187A18F300A19DEC /* CYRTextViewExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CYRTextViewExampleTests.m; sourceTree = ""; }; 105 | 3939540E187A193100A19DEC /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; 106 | 39395411187A6AFE00A19DEC /* CYRLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRLayoutManager.h; sourceTree = ""; }; 107 | 39395412187A6AFE00A19DEC /* CYRLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRLayoutManager.m; sourceTree = ""; }; 108 | 39395413187A6AFE00A19DEC /* CYRTextStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRTextStorage.h; sourceTree = ""; }; 109 | 39395414187A6AFE00A19DEC /* CYRTextStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRTextStorage.m; sourceTree = ""; }; 110 | 39395415187A6AFE00A19DEC /* CYRTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRTextView.h; sourceTree = ""; }; 111 | 39395416187A6AFE00A19DEC /* CYRTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRTextView.m; sourceTree = ""; }; 112 | 39395417187A6AFE00A19DEC /* CYRToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRToken.h; sourceTree = ""; }; 113 | 39395418187A6AFE00A19DEC /* CYRToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRToken.m; sourceTree = ""; }; 114 | 39BE42881880FDA9002BE6FF /* QEDTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QEDTextView.h; sourceTree = ""; }; 115 | 39BE42891880FDA9002BE6FF /* QEDTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QEDTextView.m; sourceTree = ""; }; 116 | DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CYRTextViewKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 117 | DA0C0E6F1C44214F001EA3FA /* CYRTextViewKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CYRTextViewKit.h; sourceTree = ""; }; 118 | DA0C0E711C44214F001EA3FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 119 | DA0C0E761C44214F001EA3FA /* CYRTextViewKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CYRTextViewKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 120 | DA0C0E7D1C44214F001EA3FA /* CYRTextViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CYRTextViewTests.swift; path = ../CYRTextViewKitTests/CYRTextViewTests.swift; sourceTree = ""; }; 121 | DA0C0E7F1C44214F001EA3FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../CYRTextViewKitTests/Info.plist; sourceTree = ""; }; 122 | DA0C0E931C4437B9001EA3FA /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 123 | /* End PBXFileReference section */ 124 | 125 | /* Begin PBXFrameworksBuildPhase section */ 126 | 393953D0187A18F300A19DEC /* Frameworks */ = { 127 | isa = PBXFrameworksBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | DA0C0E821C44214F001EA3FA /* CYRTextViewKit.framework in Frameworks */, 131 | 3939540F187A193100A19DEC /* CoreText.framework in Frameworks */, 132 | 393953D9187A18F300A19DEC /* CoreGraphics.framework in Frameworks */, 133 | 393953DB187A18F300A19DEC /* UIKit.framework in Frameworks */, 134 | 393953D7187A18F300A19DEC /* Foundation.framework in Frameworks */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | 393953F4187A18F300A19DEC /* Frameworks */ = { 139 | isa = PBXFrameworksBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | 393953F9187A18F300A19DEC /* XCTest.framework in Frameworks */, 143 | 393953FB187A18F300A19DEC /* UIKit.framework in Frameworks */, 144 | 393953FA187A18F300A19DEC /* Foundation.framework in Frameworks */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | DA0C0E691C44214F001EA3FA /* Frameworks */ = { 149 | isa = PBXFrameworksBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | DA0C0E731C44214F001EA3FA /* Frameworks */ = { 156 | isa = PBXFrameworksBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | DA0C0E771C44214F001EA3FA /* CYRTextViewKit.framework in Frameworks */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXFrameworksBuildPhase section */ 164 | 165 | /* Begin PBXGroup section */ 166 | 393953CA187A18F300A19DEC = { 167 | isa = PBXGroup; 168 | children = ( 169 | 393953DC187A18F300A19DEC /* CYRTextViewExample */, 170 | 393953FE187A18F300A19DEC /* CYRTextViewExampleTests */, 171 | DA0C0E6E1C44214F001EA3FA /* CYRTextViewKit */, 172 | DA0C0E7C1C44214F001EA3FA /* CYRTextViewKitTests */, 173 | 393953D5187A18F300A19DEC /* Frameworks */, 174 | 393953D4187A18F300A19DEC /* Products */, 175 | ); 176 | sourceTree = ""; 177 | }; 178 | 393953D4187A18F300A19DEC /* Products */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 393953D3187A18F300A19DEC /* CYRTextViewExample.app */, 182 | 393953F7187A18F300A19DEC /* CYRTextViewExampleTests.xctest */, 183 | DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */, 184 | DA0C0E761C44214F001EA3FA /* CYRTextViewKitTests.xctest */, 185 | ); 186 | name = Products; 187 | sourceTree = ""; 188 | }; 189 | 393953D5187A18F300A19DEC /* Frameworks */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 3939540E187A193100A19DEC /* CoreText.framework */, 193 | 393953D6187A18F300A19DEC /* Foundation.framework */, 194 | 393953D8187A18F300A19DEC /* CoreGraphics.framework */, 195 | 393953DA187A18F300A19DEC /* UIKit.framework */, 196 | 393953F8187A18F300A19DEC /* XCTest.framework */, 197 | ); 198 | name = Frameworks; 199 | sourceTree = ""; 200 | }; 201 | 393953DC187A18F300A19DEC /* CYRTextViewExample */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 39BE42881880FDA9002BE6FF /* QEDTextView.h */, 205 | 39BE42891880FDA9002BE6FF /* QEDTextView.m */, 206 | 393953E5187A18F300A19DEC /* AppDelegate.h */, 207 | 393953E6187A18F300A19DEC /* AppDelegate.m */, 208 | 393953EE187A18F300A19DEC /* ViewController.h */, 209 | 393953EF187A18F300A19DEC /* ViewController.m */, 210 | DA0C0E931C4437B9001EA3FA /* Launch Screen.storyboard */, 211 | 393953F1187A18F300A19DEC /* Images.xcassets */, 212 | 393953DD187A18F300A19DEC /* Supporting Files */, 213 | ); 214 | path = CYRTextViewExample; 215 | sourceTree = ""; 216 | }; 217 | 393953DD187A18F300A19DEC /* Supporting Files */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | 393953DE187A18F300A19DEC /* CYRTextViewExample-Info.plist */, 221 | 393953DF187A18F300A19DEC /* InfoPlist.strings */, 222 | 393953E2187A18F300A19DEC /* main.m */, 223 | 393953E4187A18F300A19DEC /* CYRTextViewExample-Prefix.pch */, 224 | ); 225 | name = "Supporting Files"; 226 | sourceTree = ""; 227 | }; 228 | 393953FE187A18F300A19DEC /* CYRTextViewExampleTests */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | 39395404187A18F300A19DEC /* CYRTextViewExampleTests.m */, 232 | 393953FF187A18F300A19DEC /* Supporting Files */, 233 | ); 234 | path = CYRTextViewExampleTests; 235 | sourceTree = ""; 236 | }; 237 | 393953FF187A18F300A19DEC /* Supporting Files */ = { 238 | isa = PBXGroup; 239 | children = ( 240 | 39395400187A18F300A19DEC /* CYRTextViewExampleTests-Info.plist */, 241 | 39395401187A18F300A19DEC /* InfoPlist.strings */, 242 | ); 243 | name = "Supporting Files"; 244 | sourceTree = ""; 245 | }; 246 | DA0C0E6E1C44214F001EA3FA /* CYRTextViewKit */ = { 247 | isa = PBXGroup; 248 | children = ( 249 | DA0C0E6F1C44214F001EA3FA /* CYRTextViewKit.h */, 250 | 39395411187A6AFE00A19DEC /* CYRLayoutManager.h */, 251 | 39395412187A6AFE00A19DEC /* CYRLayoutManager.m */, 252 | 39395413187A6AFE00A19DEC /* CYRTextStorage.h */, 253 | 39395414187A6AFE00A19DEC /* CYRTextStorage.m */, 254 | 39395415187A6AFE00A19DEC /* CYRTextView.h */, 255 | 39395416187A6AFE00A19DEC /* CYRTextView.m */, 256 | 39395417187A6AFE00A19DEC /* CYRToken.h */, 257 | 39395418187A6AFE00A19DEC /* CYRToken.m */, 258 | DA0C0E711C44214F001EA3FA /* Info.plist */, 259 | ); 260 | name = CYRTextViewKit; 261 | path = ../CRYTextViewKit; 262 | sourceTree = ""; 263 | }; 264 | DA0C0E7C1C44214F001EA3FA /* CYRTextViewKitTests */ = { 265 | isa = PBXGroup; 266 | children = ( 267 | DA0C0E7D1C44214F001EA3FA /* CYRTextViewTests.swift */, 268 | DA0C0E7F1C44214F001EA3FA /* Info.plist */, 269 | ); 270 | name = CYRTextViewKitTests; 271 | path = CYRTextViewTests; 272 | sourceTree = ""; 273 | }; 274 | /* End PBXGroup section */ 275 | 276 | /* Begin PBXHeadersBuildPhase section */ 277 | DA0C0E6A1C44214F001EA3FA /* Headers */ = { 278 | isa = PBXHeadersBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | DA0C0E911C44215D001EA3FA /* CYRToken.h in Headers */, 282 | DA0C0E8D1C44215D001EA3FA /* CYRTextStorage.h in Headers */, 283 | DA0C0E8F1C44215D001EA3FA /* CYRTextView.h in Headers */, 284 | DA0C0E701C44214F001EA3FA /* CYRTextViewKit.h in Headers */, 285 | DA0C0E8B1C44215D001EA3FA /* CYRLayoutManager.h in Headers */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | /* End PBXHeadersBuildPhase section */ 290 | 291 | /* Begin PBXNativeTarget section */ 292 | 393953D2187A18F300A19DEC /* CYRTextViewExample */ = { 293 | isa = PBXNativeTarget; 294 | buildConfigurationList = 39395408187A18F300A19DEC /* Build configuration list for PBXNativeTarget "CYRTextViewExample" */; 295 | buildPhases = ( 296 | 393953CF187A18F300A19DEC /* Sources */, 297 | 393953D0187A18F300A19DEC /* Frameworks */, 298 | 393953D1187A18F300A19DEC /* Resources */, 299 | DA0C0E871C44214F001EA3FA /* Embed Frameworks */, 300 | ); 301 | buildRules = ( 302 | ); 303 | dependencies = ( 304 | DA0C0E811C44214F001EA3FA /* PBXTargetDependency */, 305 | ); 306 | name = CYRTextViewExample; 307 | productName = CYRTextViewExample; 308 | productReference = 393953D3187A18F300A19DEC /* CYRTextViewExample.app */; 309 | productType = "com.apple.product-type.application"; 310 | }; 311 | 393953F6187A18F300A19DEC /* CYRTextViewExampleTests */ = { 312 | isa = PBXNativeTarget; 313 | buildConfigurationList = 3939540B187A18F300A19DEC /* Build configuration list for PBXNativeTarget "CYRTextViewExampleTests" */; 314 | buildPhases = ( 315 | 393953F3187A18F300A19DEC /* Sources */, 316 | 393953F4187A18F300A19DEC /* Frameworks */, 317 | 393953F5187A18F300A19DEC /* Resources */, 318 | ); 319 | buildRules = ( 320 | ); 321 | dependencies = ( 322 | 393953FD187A18F300A19DEC /* PBXTargetDependency */, 323 | ); 324 | name = CYRTextViewExampleTests; 325 | productName = CYRTextViewExampleTests; 326 | productReference = 393953F7187A18F300A19DEC /* CYRTextViewExampleTests.xctest */; 327 | productType = "com.apple.product-type.bundle.unit-test"; 328 | }; 329 | DA0C0E6C1C44214F001EA3FA /* CYRTextViewKit */ = { 330 | isa = PBXNativeTarget; 331 | buildConfigurationList = DA0C0E841C44214F001EA3FA /* Build configuration list for PBXNativeTarget "CYRTextViewKit" */; 332 | buildPhases = ( 333 | DA0C0E681C44214F001EA3FA /* Sources */, 334 | DA0C0E691C44214F001EA3FA /* Frameworks */, 335 | DA0C0E6A1C44214F001EA3FA /* Headers */, 336 | DA0C0E6B1C44214F001EA3FA /* Resources */, 337 | ); 338 | buildRules = ( 339 | ); 340 | dependencies = ( 341 | ); 342 | name = CYRTextViewKit; 343 | productName = CYRTextView; 344 | productReference = DA0C0E6D1C44214F001EA3FA /* CYRTextViewKit.framework */; 345 | productType = "com.apple.product-type.framework"; 346 | }; 347 | DA0C0E751C44214F001EA3FA /* CYRTextViewKitTests */ = { 348 | isa = PBXNativeTarget; 349 | buildConfigurationList = DA0C0E881C44214F001EA3FA /* Build configuration list for PBXNativeTarget "CYRTextViewKitTests" */; 350 | buildPhases = ( 351 | DA0C0E721C44214F001EA3FA /* Sources */, 352 | DA0C0E731C44214F001EA3FA /* Frameworks */, 353 | DA0C0E741C44214F001EA3FA /* Resources */, 354 | ); 355 | buildRules = ( 356 | ); 357 | dependencies = ( 358 | DA0C0E791C44214F001EA3FA /* PBXTargetDependency */, 359 | DA0C0E7B1C44214F001EA3FA /* PBXTargetDependency */, 360 | ); 361 | name = CYRTextViewKitTests; 362 | productName = CYRTextViewTests; 363 | productReference = DA0C0E761C44214F001EA3FA /* CYRTextViewKitTests.xctest */; 364 | productType = "com.apple.product-type.bundle.unit-test"; 365 | }; 366 | /* End PBXNativeTarget section */ 367 | 368 | /* Begin PBXProject section */ 369 | 393953CB187A18F300A19DEC /* Project object */ = { 370 | isa = PBXProject; 371 | attributes = { 372 | LastSwiftUpdateCheck = 0720; 373 | LastUpgradeCheck = 0720; 374 | ORGANIZATIONNAME = "Cyrillian, Inc."; 375 | TargetAttributes = { 376 | 393953F6187A18F300A19DEC = { 377 | TestTargetID = 393953D2187A18F300A19DEC; 378 | }; 379 | DA0C0E6C1C44214F001EA3FA = { 380 | CreatedOnToolsVersion = 7.2; 381 | }; 382 | DA0C0E751C44214F001EA3FA = { 383 | CreatedOnToolsVersion = 7.2; 384 | TestTargetID = 393953D2187A18F300A19DEC; 385 | }; 386 | }; 387 | }; 388 | buildConfigurationList = 393953CE187A18F300A19DEC /* Build configuration list for PBXProject "CYRTextViewExample" */; 389 | compatibilityVersion = "Xcode 3.2"; 390 | developmentRegion = English; 391 | hasScannedForEncodings = 0; 392 | knownRegions = ( 393 | en, 394 | Base, 395 | ); 396 | mainGroup = 393953CA187A18F300A19DEC; 397 | productRefGroup = 393953D4187A18F300A19DEC /* Products */; 398 | projectDirPath = ""; 399 | projectRoot = ""; 400 | targets = ( 401 | 393953D2187A18F300A19DEC /* CYRTextViewExample */, 402 | 393953F6187A18F300A19DEC /* CYRTextViewExampleTests */, 403 | DA0C0E6C1C44214F001EA3FA /* CYRTextViewKit */, 404 | DA0C0E751C44214F001EA3FA /* CYRTextViewKitTests */, 405 | ); 406 | }; 407 | /* End PBXProject section */ 408 | 409 | /* Begin PBXResourcesBuildPhase section */ 410 | 393953D1187A18F300A19DEC /* Resources */ = { 411 | isa = PBXResourcesBuildPhase; 412 | buildActionMask = 2147483647; 413 | files = ( 414 | DA0C0E941C4437B9001EA3FA /* Launch Screen.storyboard in Resources */, 415 | 393953F2187A18F300A19DEC /* Images.xcassets in Resources */, 416 | 393953E1187A18F300A19DEC /* InfoPlist.strings in Resources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | 393953F5187A18F300A19DEC /* Resources */ = { 421 | isa = PBXResourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | 39395403187A18F300A19DEC /* InfoPlist.strings in Resources */, 425 | ); 426 | runOnlyForDeploymentPostprocessing = 0; 427 | }; 428 | DA0C0E6B1C44214F001EA3FA /* Resources */ = { 429 | isa = PBXResourcesBuildPhase; 430 | buildActionMask = 2147483647; 431 | files = ( 432 | ); 433 | runOnlyForDeploymentPostprocessing = 0; 434 | }; 435 | DA0C0E741C44214F001EA3FA /* Resources */ = { 436 | isa = PBXResourcesBuildPhase; 437 | buildActionMask = 2147483647; 438 | files = ( 439 | ); 440 | runOnlyForDeploymentPostprocessing = 0; 441 | }; 442 | /* End PBXResourcesBuildPhase section */ 443 | 444 | /* Begin PBXSourcesBuildPhase section */ 445 | 393953CF187A18F300A19DEC /* Sources */ = { 446 | isa = PBXSourcesBuildPhase; 447 | buildActionMask = 2147483647; 448 | files = ( 449 | 39BE428A1880FDA9002BE6FF /* QEDTextView.m in Sources */, 450 | 393953F0187A18F300A19DEC /* ViewController.m in Sources */, 451 | 393953E7187A18F300A19DEC /* AppDelegate.m in Sources */, 452 | 393953E3187A18F300A19DEC /* main.m in Sources */, 453 | ); 454 | runOnlyForDeploymentPostprocessing = 0; 455 | }; 456 | 393953F3187A18F300A19DEC /* Sources */ = { 457 | isa = PBXSourcesBuildPhase; 458 | buildActionMask = 2147483647; 459 | files = ( 460 | 39395405187A18F300A19DEC /* CYRTextViewExampleTests.m in Sources */, 461 | ); 462 | runOnlyForDeploymentPostprocessing = 0; 463 | }; 464 | DA0C0E681C44214F001EA3FA /* Sources */ = { 465 | isa = PBXSourcesBuildPhase; 466 | buildActionMask = 2147483647; 467 | files = ( 468 | DA0C0E921C44215D001EA3FA /* CYRToken.m in Sources */, 469 | DA0C0E8C1C44215D001EA3FA /* CYRLayoutManager.m in Sources */, 470 | DA0C0E8E1C44215D001EA3FA /* CYRTextStorage.m in Sources */, 471 | DA0C0E901C44215D001EA3FA /* CYRTextView.m in Sources */, 472 | ); 473 | runOnlyForDeploymentPostprocessing = 0; 474 | }; 475 | DA0C0E721C44214F001EA3FA /* Sources */ = { 476 | isa = PBXSourcesBuildPhase; 477 | buildActionMask = 2147483647; 478 | files = ( 479 | DA0C0E7E1C44214F001EA3FA /* CYRTextViewTests.swift in Sources */, 480 | ); 481 | runOnlyForDeploymentPostprocessing = 0; 482 | }; 483 | /* End PBXSourcesBuildPhase section */ 484 | 485 | /* Begin PBXTargetDependency section */ 486 | 393953FD187A18F300A19DEC /* PBXTargetDependency */ = { 487 | isa = PBXTargetDependency; 488 | target = 393953D2187A18F300A19DEC /* CYRTextViewExample */; 489 | targetProxy = 393953FC187A18F300A19DEC /* PBXContainerItemProxy */; 490 | }; 491 | DA0C0E791C44214F001EA3FA /* PBXTargetDependency */ = { 492 | isa = PBXTargetDependency; 493 | target = DA0C0E6C1C44214F001EA3FA /* CYRTextViewKit */; 494 | targetProxy = DA0C0E781C44214F001EA3FA /* PBXContainerItemProxy */; 495 | }; 496 | DA0C0E7B1C44214F001EA3FA /* PBXTargetDependency */ = { 497 | isa = PBXTargetDependency; 498 | target = 393953D2187A18F300A19DEC /* CYRTextViewExample */; 499 | targetProxy = DA0C0E7A1C44214F001EA3FA /* PBXContainerItemProxy */; 500 | }; 501 | DA0C0E811C44214F001EA3FA /* PBXTargetDependency */ = { 502 | isa = PBXTargetDependency; 503 | target = DA0C0E6C1C44214F001EA3FA /* CYRTextViewKit */; 504 | targetProxy = DA0C0E801C44214F001EA3FA /* PBXContainerItemProxy */; 505 | }; 506 | /* End PBXTargetDependency section */ 507 | 508 | /* Begin PBXVariantGroup section */ 509 | 393953DF187A18F300A19DEC /* InfoPlist.strings */ = { 510 | isa = PBXVariantGroup; 511 | children = ( 512 | 393953E0187A18F300A19DEC /* en */, 513 | ); 514 | name = InfoPlist.strings; 515 | sourceTree = ""; 516 | }; 517 | 39395401187A18F300A19DEC /* InfoPlist.strings */ = { 518 | isa = PBXVariantGroup; 519 | children = ( 520 | 39395402187A18F300A19DEC /* en */, 521 | ); 522 | name = InfoPlist.strings; 523 | sourceTree = ""; 524 | }; 525 | /* End PBXVariantGroup section */ 526 | 527 | /* Begin XCBuildConfiguration section */ 528 | 39395406187A18F300A19DEC /* Debug */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | ALWAYS_SEARCH_USER_PATHS = NO; 532 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 533 | CLANG_CXX_LIBRARY = "libc++"; 534 | CLANG_ENABLE_MODULES = YES; 535 | CLANG_ENABLE_OBJC_ARC = YES; 536 | CLANG_WARN_BOOL_CONVERSION = YES; 537 | CLANG_WARN_CONSTANT_CONVERSION = YES; 538 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 539 | CLANG_WARN_EMPTY_BODY = YES; 540 | CLANG_WARN_ENUM_CONVERSION = YES; 541 | CLANG_WARN_INT_CONVERSION = YES; 542 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 543 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 544 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 545 | COPY_PHASE_STRIP = NO; 546 | ENABLE_TESTABILITY = YES; 547 | GCC_C_LANGUAGE_STANDARD = gnu99; 548 | GCC_DYNAMIC_NO_PIC = NO; 549 | GCC_OPTIMIZATION_LEVEL = 0; 550 | GCC_PREPROCESSOR_DEFINITIONS = ( 551 | "DEBUG=1", 552 | "$(inherited)", 553 | ); 554 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 555 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 556 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 557 | GCC_WARN_UNDECLARED_SELECTOR = YES; 558 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 559 | GCC_WARN_UNUSED_FUNCTION = YES; 560 | GCC_WARN_UNUSED_VARIABLE = YES; 561 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 562 | ONLY_ACTIVE_ARCH = YES; 563 | SDKROOT = iphoneos; 564 | TARGETED_DEVICE_FAMILY = "1,2"; 565 | }; 566 | name = Debug; 567 | }; 568 | 39395407187A18F300A19DEC /* Release */ = { 569 | isa = XCBuildConfiguration; 570 | buildSettings = { 571 | ALWAYS_SEARCH_USER_PATHS = NO; 572 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 573 | CLANG_CXX_LIBRARY = "libc++"; 574 | CLANG_ENABLE_MODULES = YES; 575 | CLANG_ENABLE_OBJC_ARC = YES; 576 | CLANG_WARN_BOOL_CONVERSION = YES; 577 | CLANG_WARN_CONSTANT_CONVERSION = YES; 578 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 579 | CLANG_WARN_EMPTY_BODY = YES; 580 | CLANG_WARN_ENUM_CONVERSION = YES; 581 | CLANG_WARN_INT_CONVERSION = YES; 582 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 583 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 584 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 585 | COPY_PHASE_STRIP = YES; 586 | ENABLE_NS_ASSERTIONS = NO; 587 | GCC_C_LANGUAGE_STANDARD = gnu99; 588 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 589 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 590 | GCC_WARN_UNDECLARED_SELECTOR = YES; 591 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 592 | GCC_WARN_UNUSED_FUNCTION = YES; 593 | GCC_WARN_UNUSED_VARIABLE = YES; 594 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 595 | SDKROOT = iphoneos; 596 | TARGETED_DEVICE_FAMILY = "1,2"; 597 | VALIDATE_PRODUCT = YES; 598 | }; 599 | name = Release; 600 | }; 601 | 39395409187A18F300A19DEC /* Debug */ = { 602 | isa = XCBuildConfiguration; 603 | buildSettings = { 604 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 605 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 606 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 607 | GCC_PREFIX_HEADER = "CYRTextViewExample/CYRTextViewExample-Prefix.pch"; 608 | INFOPLIST_FILE = "CYRTextViewExample/CYRTextViewExample-Info.plist"; 609 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 610 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 611 | PRODUCT_BUNDLE_IDENTIFIER = "com.cyrillian.${PRODUCT_NAME:rfc1034identifier}"; 612 | PRODUCT_NAME = "$(TARGET_NAME)"; 613 | WRAPPER_EXTENSION = app; 614 | }; 615 | name = Debug; 616 | }; 617 | 3939540A187A18F300A19DEC /* Release */ = { 618 | isa = XCBuildConfiguration; 619 | buildSettings = { 620 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 621 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 622 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 623 | GCC_PREFIX_HEADER = "CYRTextViewExample/CYRTextViewExample-Prefix.pch"; 624 | INFOPLIST_FILE = "CYRTextViewExample/CYRTextViewExample-Info.plist"; 625 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 626 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 627 | PRODUCT_BUNDLE_IDENTIFIER = "com.cyrillian.${PRODUCT_NAME:rfc1034identifier}"; 628 | PRODUCT_NAME = "$(TARGET_NAME)"; 629 | WRAPPER_EXTENSION = app; 630 | }; 631 | name = Release; 632 | }; 633 | 3939540C187A18F300A19DEC /* Debug */ = { 634 | isa = XCBuildConfiguration; 635 | buildSettings = { 636 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CYRTextViewExample.app/CYRTextViewExample"; 637 | FRAMEWORK_SEARCH_PATHS = ( 638 | "$(SDKROOT)/Developer/Library/Frameworks", 639 | "$(inherited)", 640 | "$(DEVELOPER_FRAMEWORKS_DIR)", 641 | ); 642 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 643 | GCC_PREFIX_HEADER = "CYRTextViewExample/CYRTextViewExample-Prefix.pch"; 644 | GCC_PREPROCESSOR_DEFINITIONS = ( 645 | "DEBUG=1", 646 | "$(inherited)", 647 | ); 648 | INFOPLIST_FILE = "CYRTextViewExampleTests/CYRTextViewExampleTests-Info.plist"; 649 | PRODUCT_BUNDLE_IDENTIFIER = "com.cyrillian.${PRODUCT_NAME:rfc1034identifier}"; 650 | PRODUCT_NAME = "$(TARGET_NAME)"; 651 | TEST_HOST = "$(BUNDLE_LOADER)"; 652 | WRAPPER_EXTENSION = xctest; 653 | }; 654 | name = Debug; 655 | }; 656 | 3939540D187A18F300A19DEC /* Release */ = { 657 | isa = XCBuildConfiguration; 658 | buildSettings = { 659 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CYRTextViewExample.app/CYRTextViewExample"; 660 | FRAMEWORK_SEARCH_PATHS = ( 661 | "$(SDKROOT)/Developer/Library/Frameworks", 662 | "$(inherited)", 663 | "$(DEVELOPER_FRAMEWORKS_DIR)", 664 | ); 665 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 666 | GCC_PREFIX_HEADER = "CYRTextViewExample/CYRTextViewExample-Prefix.pch"; 667 | INFOPLIST_FILE = "CYRTextViewExampleTests/CYRTextViewExampleTests-Info.plist"; 668 | PRODUCT_BUNDLE_IDENTIFIER = "com.cyrillian.${PRODUCT_NAME:rfc1034identifier}"; 669 | PRODUCT_NAME = "$(TARGET_NAME)"; 670 | TEST_HOST = "$(BUNDLE_LOADER)"; 671 | WRAPPER_EXTENSION = xctest; 672 | }; 673 | name = Release; 674 | }; 675 | DA0C0E851C44214F001EA3FA /* Debug */ = { 676 | isa = XCBuildConfiguration; 677 | buildSettings = { 678 | CLANG_WARN_UNREACHABLE_CODE = YES; 679 | CURRENT_PROJECT_VERSION = 1; 680 | DEBUG_INFORMATION_FORMAT = dwarf; 681 | DEFINES_MODULE = YES; 682 | DYLIB_COMPATIBILITY_VERSION = 1; 683 | DYLIB_CURRENT_VERSION = 1; 684 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 685 | ENABLE_STRICT_OBJC_MSGSEND = YES; 686 | GCC_NO_COMMON_BLOCKS = YES; 687 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 688 | INFOPLIST_FILE = "$(SRCROOT)/../CRYTextViewKit/Info.plist"; 689 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 690 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 691 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 692 | MTL_ENABLE_DEBUG_INFO = YES; 693 | PRODUCT_BUNDLE_IDENTIFIER = com.dustinpfannenstiel.CYRTextView; 694 | PRODUCT_NAME = "$(TARGET_NAME)"; 695 | SKIP_INSTALL = YES; 696 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 697 | VERSIONING_SYSTEM = "apple-generic"; 698 | VERSION_INFO_PREFIX = ""; 699 | }; 700 | name = Debug; 701 | }; 702 | DA0C0E861C44214F001EA3FA /* Release */ = { 703 | isa = XCBuildConfiguration; 704 | buildSettings = { 705 | CLANG_WARN_UNREACHABLE_CODE = YES; 706 | COPY_PHASE_STRIP = NO; 707 | CURRENT_PROJECT_VERSION = 1; 708 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 709 | DEFINES_MODULE = YES; 710 | DYLIB_COMPATIBILITY_VERSION = 1; 711 | DYLIB_CURRENT_VERSION = 1; 712 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 713 | ENABLE_STRICT_OBJC_MSGSEND = YES; 714 | GCC_NO_COMMON_BLOCKS = YES; 715 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 716 | INFOPLIST_FILE = "$(SRCROOT)/../CRYTextViewKit/Info.plist"; 717 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 718 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 719 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 720 | MTL_ENABLE_DEBUG_INFO = NO; 721 | PRODUCT_BUNDLE_IDENTIFIER = com.dustinpfannenstiel.CYRTextView; 722 | PRODUCT_NAME = "$(TARGET_NAME)"; 723 | SKIP_INSTALL = YES; 724 | VERSIONING_SYSTEM = "apple-generic"; 725 | VERSION_INFO_PREFIX = ""; 726 | }; 727 | name = Release; 728 | }; 729 | DA0C0E891C44214F001EA3FA /* Debug */ = { 730 | isa = XCBuildConfiguration; 731 | buildSettings = { 732 | CLANG_WARN_UNREACHABLE_CODE = YES; 733 | DEBUG_INFORMATION_FORMAT = dwarf; 734 | ENABLE_STRICT_OBJC_MSGSEND = YES; 735 | GCC_NO_COMMON_BLOCKS = YES; 736 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 737 | INFOPLIST_FILE = CYRTextViewKitTests/Info.plist; 738 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 739 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 740 | MTL_ENABLE_DEBUG_INFO = YES; 741 | PRODUCT_BUNDLE_IDENTIFIER = com.dustinpfannenstiel.CYRTextViewTests; 742 | PRODUCT_NAME = "$(TARGET_NAME)"; 743 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 744 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CYRTextViewExample.app/CYRTextViewExample"; 745 | }; 746 | name = Debug; 747 | }; 748 | DA0C0E8A1C44214F001EA3FA /* Release */ = { 749 | isa = XCBuildConfiguration; 750 | buildSettings = { 751 | CLANG_WARN_UNREACHABLE_CODE = YES; 752 | COPY_PHASE_STRIP = NO; 753 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 754 | ENABLE_STRICT_OBJC_MSGSEND = YES; 755 | GCC_NO_COMMON_BLOCKS = YES; 756 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 757 | INFOPLIST_FILE = CYRTextViewKitTests/Info.plist; 758 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 759 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 760 | MTL_ENABLE_DEBUG_INFO = NO; 761 | PRODUCT_BUNDLE_IDENTIFIER = com.dustinpfannenstiel.CYRTextViewTests; 762 | PRODUCT_NAME = "$(TARGET_NAME)"; 763 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CYRTextViewExample.app/CYRTextViewExample"; 764 | }; 765 | name = Release; 766 | }; 767 | /* End XCBuildConfiguration section */ 768 | 769 | /* Begin XCConfigurationList section */ 770 | 393953CE187A18F300A19DEC /* Build configuration list for PBXProject "CYRTextViewExample" */ = { 771 | isa = XCConfigurationList; 772 | buildConfigurations = ( 773 | 39395406187A18F300A19DEC /* Debug */, 774 | 39395407187A18F300A19DEC /* Release */, 775 | ); 776 | defaultConfigurationIsVisible = 0; 777 | defaultConfigurationName = Release; 778 | }; 779 | 39395408187A18F300A19DEC /* Build configuration list for PBXNativeTarget "CYRTextViewExample" */ = { 780 | isa = XCConfigurationList; 781 | buildConfigurations = ( 782 | 39395409187A18F300A19DEC /* Debug */, 783 | 3939540A187A18F300A19DEC /* Release */, 784 | ); 785 | defaultConfigurationIsVisible = 0; 786 | defaultConfigurationName = Release; 787 | }; 788 | 3939540B187A18F300A19DEC /* Build configuration list for PBXNativeTarget "CYRTextViewExampleTests" */ = { 789 | isa = XCConfigurationList; 790 | buildConfigurations = ( 791 | 3939540C187A18F300A19DEC /* Debug */, 792 | 3939540D187A18F300A19DEC /* Release */, 793 | ); 794 | defaultConfigurationIsVisible = 0; 795 | defaultConfigurationName = Release; 796 | }; 797 | DA0C0E841C44214F001EA3FA /* Build configuration list for PBXNativeTarget "CYRTextViewKit" */ = { 798 | isa = XCConfigurationList; 799 | buildConfigurations = ( 800 | DA0C0E851C44214F001EA3FA /* Debug */, 801 | DA0C0E861C44214F001EA3FA /* Release */, 802 | ); 803 | defaultConfigurationIsVisible = 0; 804 | }; 805 | DA0C0E881C44214F001EA3FA /* Build configuration list for PBXNativeTarget "CYRTextViewKitTests" */ = { 806 | isa = XCConfigurationList; 807 | buildConfigurations = ( 808 | DA0C0E891C44214F001EA3FA /* Debug */, 809 | DA0C0E8A1C44214F001EA3FA /* Release */, 810 | ); 811 | defaultConfigurationIsVisible = 0; 812 | }; 813 | /* End XCConfigurationList section */ 814 | }; 815 | rootObject = 393953CB187A18F300A19DEC /* Project object */; 816 | } 817 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 18 | self.window = window; 19 | 20 | ViewController *viewController = [ViewController new]; 21 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; 22 | 23 | self.window.rootViewController = navigationController; 24 | [self.window makeKeyAndVisible]; 25 | 26 | return YES; 27 | } 28 | 29 | - (void)applicationWillResignActive:(UIApplication *)application 30 | { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 33 | } 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application 36 | { 37 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | - (void)applicationWillEnterForeground:(UIApplication *)application 42 | { 43 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | - (void)applicationDidBecomeActive:(UIApplication *)application 47 | { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application 52 | { 53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/CYRTextViewExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarHidden 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | UIInterfaceOrientationPortraitUpsideDown 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/CYRTextViewExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifdef __OBJC__ 10 | #import 11 | #import 12 | #endif 13 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Example/CYRTextViewExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /Example/CYRTextViewExample/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/QEDTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // QEDTextView.h 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/10/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | @import CYRTextViewKit; 10 | 11 | @interface QEDTextView : CYRTextView 12 | 13 | @property (nonatomic, strong) UIFont *defaultFont; 14 | @property (nonatomic, strong) UIFont *boldFont; 15 | @property (nonatomic, strong) UIFont *italicFont; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/QEDTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // QEDTextView.m 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/10/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import "QEDTextView.h" 10 | 11 | #import 12 | 13 | #define RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f] 14 | 15 | @implementation QEDTextView 16 | 17 | #pragma mark - Initialization & Setup 18 | 19 | - (id)initWithFrame:(CGRect)frame 20 | { 21 | self = [super initWithFrame:frame]; 22 | 23 | if (self) 24 | { 25 | [self commonSetup]; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | - (void)commonSetup 32 | { 33 | _defaultFont = [UIFont systemFontOfSize:14.0f]; 34 | _boldFont = [UIFont boldSystemFontOfSize:14.0f]; 35 | _italicFont = [UIFont fontWithName:@"HelveticaNeue-Oblique" size:14.0f]; 36 | 37 | self.font = _defaultFont; 38 | self.textColor = [UIColor blackColor]; 39 | 40 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(defaultFont)) options:NSKeyValueObservingOptionNew context:0]; 41 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(boldFont)) options:NSKeyValueObservingOptionNew context:0]; 42 | [self addObserver:self forKeyPath:NSStringFromSelector(@selector(italicFont)) options:NSKeyValueObservingOptionNew context:0]; 43 | 44 | if (_italicFont == nil && ([UIFontDescriptor class] != nil)) 45 | { 46 | // This works around a bug in 7.0.3 where HelveticaNeue-Italic is not present as a UIFont option 47 | _italicFont = (__bridge_transfer UIFont*)CTFontCreateWithName(CFSTR("HelveticaNeue-Italic"), 14.0f, NULL); 48 | } 49 | 50 | self.tokens = [self solverTokens]; 51 | } 52 | 53 | 54 | - (NSArray *)solverTokens 55 | { 56 | NSArray *solverTokens = @[ 57 | [CYRToken tokenWithName:@"special_numbers" 58 | expression:@"[ʝ]" 59 | attributes:@{ 60 | NSForegroundColorAttributeName : RGB(0, 0, 255) 61 | }], 62 | [CYRToken tokenWithName:@"mod" 63 | expression:@"\bmod\b" 64 | attributes:@{ 65 | NSForegroundColorAttributeName : RGB(245, 0, 110) 66 | }], 67 | [CYRToken tokenWithName:@"string" 68 | expression:@"\".*?(\"|$)" 69 | attributes:@{ 70 | NSForegroundColorAttributeName : RGB(24, 110, 109) 71 | }], 72 | [CYRToken tokenWithName:@"hex_1" 73 | expression:@"\\$[\\d a-f]+" 74 | attributes:@{ 75 | NSForegroundColorAttributeName : RGB(0, 0, 255) 76 | }], 77 | [CYRToken tokenWithName:@"octal_1" 78 | expression:@"&[0-7]+" 79 | attributes:@{ 80 | NSForegroundColorAttributeName : RGB(0, 0, 255) 81 | }], 82 | [CYRToken tokenWithName:@"binary_1" 83 | expression:@"%[01]+" 84 | attributes:@{ 85 | NSForegroundColorAttributeName : RGB(0, 0, 255) 86 | }], 87 | [CYRToken tokenWithName:@"hex_2" 88 | expression:@"0x[0-9 a-f]+" 89 | attributes:@{ 90 | NSForegroundColorAttributeName : RGB(0, 0, 255) 91 | }], 92 | [CYRToken tokenWithName:@"octal_2" 93 | expression:@"0o[0-7]+" 94 | attributes:@{ 95 | NSForegroundColorAttributeName : RGB(0, 0, 255) 96 | }], 97 | [CYRToken tokenWithName:@"binary_2" 98 | expression:@"0b[01]+" 99 | attributes:@{ 100 | NSForegroundColorAttributeName : RGB(0, 0, 255) 101 | }], 102 | [CYRToken tokenWithName:@"float" 103 | expression:@"\\d+\\.?\\d+e[\\+\\-]?\\d+|\\d+\\.\\d+|∞" 104 | attributes:@{ 105 | NSForegroundColorAttributeName : RGB(0, 0, 255) 106 | }], 107 | [CYRToken tokenWithName:@"integer" 108 | expression:@"\\d+" 109 | attributes:@{ 110 | NSForegroundColorAttributeName : RGB(0, 0, 255) 111 | }], 112 | [CYRToken tokenWithName:@"operator" 113 | expression:@"[/\\*,\\;:=<>\\+\\-\\^!·≤≥]" 114 | attributes:@{ 115 | NSForegroundColorAttributeName : RGB(245, 0, 110) 116 | }], 117 | [CYRToken tokenWithName:@"round_brackets" 118 | expression:@"[\\(\\)]" 119 | attributes:@{ 120 | NSForegroundColorAttributeName : RGB(161, 75, 0) 121 | }], 122 | [CYRToken tokenWithName:@"square_brackets" 123 | expression:@"[\\[\\]]" 124 | attributes:@{ 125 | NSForegroundColorAttributeName : RGB(105, 0, 0), 126 | NSFontAttributeName : self.boldFont 127 | }], 128 | [CYRToken tokenWithName:@"absolute_brackets" 129 | expression:@"[|]" 130 | attributes:@{ 131 | NSForegroundColorAttributeName : RGB(104, 0, 111) 132 | }], 133 | [CYRToken tokenWithName:@"reserved_words" 134 | expression:@"(abs|acos|acosh|asin|asinh|atan|atanh|atomicweight|ceil|complex|cos|cosh|crandom|deriv|erf|erfc|exp|eye|floor|frac|gamma|gaussel|getconst|imag|inf|integ|integhq|inv|ln|log10|log2|machineprecision|max|maximize|min|minimize|molecularweight|ncum|ones|pi|plot|random|real|round|sgn|sin|sqr|sinh|sqrt|tan|tanh|transpose|trunc|var|zeros)" 135 | attributes:@{ 136 | NSForegroundColorAttributeName : RGB(104, 0, 111), 137 | NSFontAttributeName : self.boldFont 138 | }], 139 | [CYRToken tokenWithName:@"chart_parameters" 140 | expression:@"(chartheight|charttitle|chartwidth|color|seriesname|showlegend|showxmajorgrid|showxminorgrid|showymajorgrid|showyminorgrid|transparency|thickness|xautoscale|xaxisrange|xlabel|xlogscale|xrange|yautoscale|yaxisrange|ylabel|ylogscale|yrange)" 141 | attributes:@{ 142 | NSForegroundColorAttributeName : RGB(11, 81, 195), 143 | }], 144 | [CYRToken tokenWithName:@"comment" 145 | expression:@"//.*" 146 | attributes:@{ 147 | NSForegroundColorAttributeName : RGB(31, 131, 0), 148 | NSFontAttributeName : self.italicFont 149 | }] 150 | ]; 151 | 152 | return solverTokens; 153 | } 154 | 155 | 156 | #pragma mark - Cleanup 157 | 158 | - (void)dealloc 159 | { 160 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(defaultFont))]; 161 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(boldFont))]; 162 | [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(italicFont))]; 163 | } 164 | 165 | 166 | #pragma mark - KVO 167 | 168 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 169 | { 170 | if ([keyPath isEqualToString:NSStringFromSelector(@selector(defaultFont))] || 171 | [keyPath isEqualToString:NSStringFromSelector(@selector(boldFont))] || 172 | [keyPath isEqualToString:NSStringFromSelector(@selector(italicFont))]) 173 | { 174 | // Reset the tokens, this will clear any existing formatting 175 | self.tokens = [self solverTokens]; 176 | } 177 | else 178 | { 179 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 180 | } 181 | } 182 | 183 | 184 | #pragma mark - Overrides 185 | 186 | - (void)setDefaultFont:(UIFont *)defaultFont 187 | { 188 | _defaultFont = defaultFont; 189 | self.font = defaultFont; 190 | } 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "QEDTextView.h" 12 | 13 | @interface ViewController () 14 | 15 | @property (nonatomic, strong) QEDTextView *textView; 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | #pragma mark - View Lifecycle 22 | 23 | - (void)viewDidLoad 24 | { 25 | [super viewDidLoad]; 26 | 27 | self.navigationItem.title = @"CYRTextView"; 28 | 29 | self.view.backgroundColor = [UIColor whiteColor]; 30 | 31 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 32 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 33 | 34 | QEDTextView *textView = [[QEDTextView alloc] initWithFrame:self.view.bounds]; 35 | textView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 36 | textView.delegate = self; 37 | 38 | self.textView = textView; 39 | 40 | [self.view addSubview:textView]; 41 | 42 | self.textView.text = @"// Test comment\n\n"\ 43 | @"// Let's solve our first equation\n"\ 44 | @"x = 1 / (1 + x) // equation to solve for x\n"\ 45 | @"x > 0 // restrict to positive root\n\n"\ 46 | @"// Let's create a user function\n"\ 47 | @"// The standard function random returns a random value between 0 an 1\n"\ 48 | @"g(x) := 0.005 * (x + 1) * (x - 1) + 0.1 * (random - 0.5)\n\n"\ 49 | @"// Now let's plot the two functions together on one chart\n"\ 50 | @"plot f(x), g(x)"; 51 | } 52 | 53 | 54 | #pragma mark - Notification Handlers 55 | 56 | - (void)keyboardWillShow:(NSNotification*)aNotification 57 | { 58 | UIBarButtonItem *dismissButton = [[UIBarButtonItem alloc] initWithTitle:@"Dismiss" style:UIBarButtonItemStyleDone target:self action:@selector(dismissKeyboard)]; 59 | 60 | [self.navigationItem setRightBarButtonItem:dismissButton animated:YES]; 61 | 62 | [self moveTextViewForKeyboard:aNotification up:YES]; 63 | } 64 | 65 | - (void)keyboardWillHide:(NSNotification*)aNotification 66 | { 67 | self.navigationItem.rightBarButtonItem = nil; 68 | [self moveTextViewForKeyboard:aNotification up:NO]; 69 | } 70 | 71 | 72 | #pragma mark - Convenience 73 | 74 | - (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up 75 | { 76 | NSDictionary* userInfo = [aNotification userInfo]; 77 | NSTimeInterval animationDuration; 78 | UIViewAnimationCurve animationCurve; 79 | CGRect keyboardEndFrame; 80 | 81 | [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; 82 | [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; 83 | [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; 84 | 85 | [UIView beginAnimations:nil context:nil]; 86 | [UIView setAnimationDuration:animationDuration]; 87 | [UIView setAnimationCurve:animationCurve]; 88 | 89 | CGRect newFrame = _textView.frame; 90 | CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil]; 91 | newFrame.size.height -= keyboardFrame.size.height * (up?1:-1); 92 | _textView.frame = newFrame; 93 | 94 | [UIView commitAnimations]; 95 | } 96 | 97 | - (void)dismissKeyboard 98 | { 99 | [_textView resignFirstResponder]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/CYRTextViewExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CYRTextViewExample 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Example/CYRTextViewExampleTests/CYRTextViewExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/CYRTextViewExampleTests/CYRTextViewExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextViewExampleTests.m 3 | // CYRTextViewExampleTests 4 | // 5 | // Created by Illya Busigin on 1/5/14. 6 | // Copyright (c) 2014 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CYRTextViewExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation CYRTextViewExampleTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Example/CYRTextViewExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/CYRTextViewKitTests/CYRTextViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CYRTextViewTests.swift 3 | // CYRTextViewTests 4 | // 5 | // Created by Dustin Pfannenstiel on 1/11/16. 6 | // Copyright © 2016 Cyrillian, Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import CYRTextViewKit 11 | 12 | class CYRTextViewTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/CYRTextViewKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Cyrillian, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CYRTextView 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/CYRTextView.svg?style=flat)](https://github.com/illyabusigin/CYRTextView) 4 | [![License](https://img.shields.io/cocoapods/l/CYRTextView.svg?style=flat)](https://github.com/illyabusigin/CYRTextView) 5 | [![Platform](https://img.shields.io/cocoapods/p/CYRTextView.svg?style=flat)](https://github.com/illyabusigin/CYRTextView) 6 | 7 | by **Illya Busigin** 8 | 9 | - Visit my blog at [http://illyabusigin.com/](http://illyabusigin.com/) 10 | - Follow [@illyabusigin on Twitter](http://twitter.com/illyabusigin) 11 | 12 | Purpose 13 | -------------- 14 | 15 | CYRTextView is a UITextView subclass that implements a variety of features that are relevant to a syntax or code text view. There are many subclasses of UITextView out there with the release of TextKit but none that are specifically tailored towards a code/syntax view. CYRTextView aims to change this. Features include: 16 | - Regular expression based text highlighting with support for multiple text attributes for each expression 17 | - Line numbers 18 | - Gesture based navigation 19 | 20 | Long term, I would like to turn CYRTextView into a full fledged code editor component with code folding, markers, annotation, and more. 21 | 22 | 23 | Screenshot 24 | -------------- 25 | 26 | 27 | 28 | Requirements 29 | ----------------------------- 30 | 31 | iOS 7.0 or later (**with ARC**) for iPhone, iPad and iPod touch 32 | 33 | 34 | Installation 35 | --------------- 36 | 37 | To use CYRTextView, just drag the class files into your project and add the CoreText framework. You can create CYRTextView instances programatically, or create them in Interface Builder by dragging an ordinary UITextView into your view and setting its class to CYRTextView. 38 | 39 | If you are using Interface Builder, to set the custom properties of CYRTextView (ones that are not supported by regular UIViews) either create an IBOutlet for your view and set the properties in code, or use the User Defined Runtime Attributes feature in Interface Builder (introduced in Xcode 4.2 for iOS 5+). 40 | 41 | **NOTE**: The current version (0.4.0) is alpha quality at best. Use at your own risk! 42 | 43 | 44 | Example 45 | --------------- 46 | 47 | CYRTextView includes an example project that demonstrates how to subclass CYRTextView to provide highlighting behavior for multiple attributes with a default set of normal, bold, and italic fonts. 48 | 49 | 50 | Bugs & Feature Requests 51 | --------------- 52 | 53 | There is **no support** offered with this component. If you would like a feature or find a bug, please submit a feature request through the [GitHub issue tracker](http://github.com/illyabusigin/CYRTextView/issues). 54 | 55 | Pull-requests for bug-fixes and features are welcome! 56 | 57 | Attribution 58 | -------------- 59 | 60 | CYRTextView uses portions of code from the following sources. 61 | 62 | | Component | Description | License | 63 | | ------------- |:-------------:| -----:| 64 | | [NLTextView](https://github.com/srijs/NLTextView) | A UITextView with Syntax Highlighting and Pan-Gesture Navigation / Selection | [MIT](https://github.com/srijs/NLTextView/blob/master/NLTextView/NLTextView.h) | 65 | | [TextKit_LineNumbers](https://github.com/alldritt/TextKit_LineNumbers) | iOS7 Text Kit - Text View with Line Numbers | [MIT](https://github.com/alldritt/TextKit_LineNumbers) | 66 | 67 | -------------------------------------------------------------------------------- /Screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyabusigin/CYRTextView/684ba5707637cf2a15952fa8922f6fa944b164e2/Screenshots/1.png --------------------------------------------------------------------------------