├── LineNumberTextView ├── LineNumberLayoutManager.h ├── LineNumberLayoutManager.m ├── LineNumberTextView.h ├── LineNumberTextView.m ├── LineNumberTextViewWrapper.h └── LineNumberTextViewWrapper.m ├── README.md ├── Screenshot.png ├── TextKit_LineNumbers.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── mall.xcuserdatad │ └── xcschemes │ ├── TextKit_LineNumbers.xcscheme │ └── xcschememanagement.plist ├── TextKit_LineNumbers ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── Main_iPad.storyboard │ └── Main_iPhone.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── Sample.rtf ├── TextKit_LineNumbers-Info.plist ├── TextKit_LineNumbers-Prefix.pch ├── ViewController.h ├── ViewController.m ├── en.lproj │ └── InfoPlist.strings └── main.m ├── TextKit_LineNumbers_swift.xcodeproj └── project.pbxproj └── TextKit_LineNumbers_swift ├── AppDelegate.swift ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist └── ViewController.swift /LineNumberTextView/LineNumberLayoutManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberLayoutManager.h 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LineNumberLayoutManager : NSLayoutManager 12 | /// Defaults to system font, 10pt. 13 | @property (nonatomic) UIFont *lineNumberFont; 14 | 15 | /// Defaults to white. 16 | @property (nonatomic) UIColor *lineNumberTextColor; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /LineNumberTextView/LineNumberLayoutManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberLayoutManager.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import "LineNumberLayoutManager.h" 10 | 11 | @interface LineNumberLayoutManager () 12 | 13 | @property (nonatomic) NSUInteger lastParaLocation; 14 | @property (nonatomic) NSUInteger lastParaNumber; 15 | 16 | @end 17 | 18 | @implementation LineNumberLayoutManager 19 | 20 | - (instancetype)init { 21 | self = [super init]; 22 | [self initializeLineNumberLayoutManager]; 23 | return self; 24 | } 25 | 26 | - (nullable instancetype)initWithCoder:(NSCoder *)coder { 27 | self = [super initWithCoder:coder]; 28 | [self initializeLineNumberLayoutManager]; 29 | return self; 30 | } 31 | 32 | - (void)initializeLineNumberLayoutManager { 33 | _lineNumberFont = [UIFont systemFontOfSize:10.0]; 34 | _lineNumberTextColor = [UIColor whiteColor]; 35 | } 36 | 37 | - (NSUInteger) _paraNumberForRange:(NSRange) charRange { 38 | // NSString does not provide a means of efficiently determining the paragraph number of a range of text. This code 39 | // attempts to optimize what would normally be a series linear searches by keeping track of the last paragraph number 40 | // found and uses that as the starting point for next paragraph number search. This works (mostly) because we 41 | // are generally asked for continguous increasing sequences of paragraph numbers. Also, this code is called in the 42 | // course of drawing a pagefull of text, and so even when moving back, the number of paragraphs to search for is 43 | // relativly low, even in really long bodies of text. 44 | // 45 | // This all falls down when the user edits the text, and can potentially invalidate the cached paragraph number which 46 | // causes a (potentially lengthy) search from the beginning of the string. 47 | 48 | if (charRange.location == self.lastParaLocation) 49 | return self.lastParaNumber; 50 | else if (charRange.location < self.lastParaLocation) { 51 | // We need to look backwards from the last known paragraph for the new paragraph range. This generally happens 52 | // when the text in the UITextView scrolls downward, revaling paragraphs before/above the ones previously drawn. 53 | 54 | NSString* s = self.textStorage.string; 55 | __block NSUInteger paraNumber = self.lastParaNumber; 56 | 57 | [s enumerateSubstringsInRange:NSMakeRange(charRange.location, self.lastParaLocation - charRange.location) 58 | options:NSStringEnumerationByParagraphs | 59 | NSStringEnumerationSubstringNotRequired | 60 | NSStringEnumerationReverse 61 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){ 62 | if (enclosingRange.location <= charRange.location) { 63 | *stop = YES; 64 | } 65 | --paraNumber; 66 | }]; 67 | 68 | self.lastParaLocation = charRange.location; 69 | self.lastParaNumber = paraNumber; 70 | return paraNumber; 71 | } 72 | else { 73 | // We need to look forward from the last known paragraph for the new paragraph range. This generally happens 74 | // when the text in the UITextView scrolls upwards, revealing paragraphs that follow the ones previously drawn. 75 | 76 | NSString* s = self.textStorage.string; 77 | __block NSUInteger paraNumber = self.lastParaNumber; 78 | 79 | [s enumerateSubstringsInRange:NSMakeRange(self.lastParaLocation, charRange.location - self.lastParaLocation) 80 | options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired 81 | usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){ 82 | if (enclosingRange.location >= charRange.location) { 83 | *stop = YES; 84 | } 85 | ++paraNumber; 86 | }]; 87 | 88 | self.lastParaLocation = charRange.location; 89 | self.lastParaNumber = paraNumber; 90 | return paraNumber; 91 | } 92 | } 93 | 94 | - (void)processEditingForTextStorage:(NSTextStorage *)textStorage edited:(NSTextStorageEditActions)editMask range:(NSRange)newCharRange changeInLength:(NSInteger)delta invalidatedRange:(NSRange)invalidatedCharRange { 95 | [super processEditingForTextStorage:textStorage edited:editMask range:newCharRange changeInLength:delta invalidatedRange:invalidatedCharRange]; 96 | 97 | if (invalidatedCharRange.location < self.lastParaLocation) { 98 | // When the backing store is edited ahead the cached paragraph location, invalidate the cache and force a complete 99 | // recalculation. We cannot be much smarter than this because we don't know how many paragraphs have been deleted 100 | // since the text has already been removed from the backing store. 101 | 102 | self.lastParaLocation = 0; 103 | self.lastParaNumber = 0; 104 | } 105 | } 106 | 107 | - (void) drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin { 108 | [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin]; 109 | 110 | // Draw line numbers. Note that the background for line number gutter is drawn by the LineNumberTextView class. 111 | NSDictionary* atts = @{NSFontAttributeName : _lineNumberFont, 112 | NSForegroundColorAttributeName : _lineNumberTextColor}; 113 | __block CGRect gutterRect = CGRectZero; 114 | __block NSUInteger paraNumber; 115 | 116 | [self enumerateLineFragmentsForGlyphRange:glyphsToShow 117 | usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) { 118 | NSRange charRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:nil]; 119 | NSRange paraRange = [self.textStorage.string paragraphRangeForRange:charRange]; 120 | 121 | // Only draw line numbers for the paragraph's first line fragment. Subsiquent fragments are wrapped portions of the paragraph and don't 122 | // get the line number. 123 | if (charRange.location == paraRange.location) { 124 | gutterRect = CGRectOffset(CGRectMake(0, rect.origin.y, 40.0, rect.size.height), origin.x, origin.y); 125 | paraNumber = [self _paraNumberForRange:charRange]; 126 | NSString* ln = [NSString stringWithFormat:@"%ld", (unsigned long) paraNumber + 1]; 127 | CGSize size = [ln sizeWithAttributes:atts]; 128 | 129 | [ln drawInRect:CGRectOffset(gutterRect, CGRectGetWidth(gutterRect) - 4 - size.width, (CGRectGetHeight(gutterRect) - size.height) / 2.0) 130 | withAttributes:atts]; 131 | } 132 | }]; 133 | 134 | // Deal with the special case of an empty last line where enumerateLineFragmentsForGlyphRange has no line 135 | // fragments to draw. 136 | if (NSMaxRange(glyphsToShow) > self.numberOfGlyphs) { 137 | NSString* ln = [NSString stringWithFormat:@"%ld", (unsigned long) paraNumber + 2]; 138 | CGSize size = [ln sizeWithAttributes:atts]; 139 | 140 | gutterRect = CGRectOffset(gutterRect, 0.0, CGRectGetHeight(gutterRect)); 141 | [ln drawInRect:CGRectOffset(gutterRect, CGRectGetWidth(gutterRect) - 4 - size.width, (CGRectGetHeight(gutterRect) - size.height) / 2.0) 142 | withAttributes:atts]; 143 | } 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /LineNumberTextView/LineNumberTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberTextView.h 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | #define kLineNumberGutterWidth 40.0 13 | 14 | @interface LineNumberTextView : UITextView 15 | 16 | /// Defaults to system font, 10pt. 17 | @property (nonatomic) UIFont *lineNumberFont; 18 | 19 | /// Defaults to gray. 20 | @property (nonatomic) UIColor *lineNumberBackgroundColor; 21 | 22 | /// Defaults to dark gray. 23 | @property (nonatomic) UIColor *lineNumberBorderColor; 24 | 25 | /// Defaults to white. 26 | @property (nonatomic) UIColor *lineNumberTextColor; 27 | 28 | - (id)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /LineNumberTextView/LineNumberTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberTextView.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import "LineNumberTextView.h" 10 | #import "LineNumberLayoutManager.h" 11 | 12 | 13 | @implementation LineNumberTextView 14 | 15 | - (id)initWithFrame:(CGRect) frame { 16 | 17 | NSTextStorage* ts = [[NSTextStorage alloc] init]; 18 | LineNumberLayoutManager* lm = [[LineNumberLayoutManager alloc] init]; 19 | NSTextContainer* tc = [[NSTextContainer alloc] initWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; 20 | 21 | // Wrap text to the text view's frame 22 | tc.widthTracksTextView = YES; 23 | 24 | // Exclude the line number gutter from the display area available for text display. 25 | tc.exclusionPaths = @[[UIBezierPath bezierPathWithRect:CGRectMake(0.0, 0.0, kLineNumberGutterWidth, CGFLOAT_MAX)]]; 26 | 27 | [lm addTextContainer:tc]; 28 | [ts addLayoutManager:lm]; 29 | 30 | if ((self = [super initWithFrame:frame textContainer:tc])) { 31 | self.contentMode = UIViewContentModeRedraw; // cause drawRect: to be called on frame resizing and device rotation 32 | 33 | // I'm finding that this text view is not behaving properly when typing into a new line at the end of the body 34 | // of text. The cursor is positioned inward, and then jumps back to the proper position when a character is 35 | // typed. I'm sure this has something to do with the view's typingAttributes or one of the delegate methods. 36 | 37 | //self.typingAttributes = @{NSFontAttributeName : [UIFont systemFontOfSize:16.0], 38 | // NSParagraphStyleAttributeName : [NSParagraphStyle defaultParagraphStyle]}; 39 | _lineNumberBackgroundColor = [UIColor grayColor]; 40 | _lineNumberBorderColor = [UIColor darkGrayColor]; 41 | } 42 | return self; 43 | } 44 | 45 | - (void) drawRect:(CGRect)rect { 46 | 47 | // Drag the line number gutter background. The line numbers them selves are drawn by LineNumberLayoutManager. 48 | CGContextRef context = UIGraphicsGetCurrentContext(); 49 | CGRect bounds = self.bounds; 50 | 51 | CGContextSetFillColorWithColor(context, _lineNumberBackgroundColor.CGColor); 52 | CGContextFillRect(context, CGRectMake(bounds.origin.x, bounds.origin.y, kLineNumberGutterWidth, bounds.size.height)); 53 | 54 | CGContextSetStrokeColorWithColor(context, _lineNumberBorderColor.CGColor); 55 | CGContextSetLineWidth(context, 0.5); 56 | CGContextStrokeRect(context, CGRectMake(bounds.origin.x + 39.5, bounds.origin.y, 0.5, CGRectGetHeight(bounds))); 57 | 58 | [super drawRect:rect]; 59 | } 60 | 61 | - (UIFont *)lineNumberFont { 62 | LineNumberLayoutManager* lm = (LineNumberLayoutManager*) self.layoutManager; 63 | return lm.lineNumberFont; 64 | } 65 | 66 | - (void)setLineNumberFont:(UIFont *)lineNumberFont { 67 | LineNumberLayoutManager* lm = (LineNumberLayoutManager*) self.layoutManager; 68 | if (![lm.lineNumberFont isEqual:lineNumberFont]) { 69 | lm.lineNumberFont = lineNumberFont; 70 | [self setNeedsDisplay]; 71 | } 72 | } 73 | 74 | - (UIColor *)lineNumberTextColor { 75 | LineNumberLayoutManager* lm = (LineNumberLayoutManager*) self.layoutManager; 76 | return lm.lineNumberTextColor; 77 | } 78 | 79 | - (void)setLineNumberTextColor:(UIColor *)lineNumberTextColor { 80 | LineNumberLayoutManager* lm = (LineNumberLayoutManager*) self.layoutManager; 81 | if (![lm.lineNumberTextColor isEqual:lineNumberTextColor]) { 82 | lm.lineNumberTextColor = lineNumberTextColor; 83 | [self setNeedsDisplay]; 84 | } 85 | } 86 | 87 | - (void)setLineNumberBackgroundColor:(UIColor *)lineNumberBackgroundColor { 88 | if (![_lineNumberBackgroundColor isEqual:lineNumberBackgroundColor]) { 89 | _lineNumberBackgroundColor = lineNumberBackgroundColor; 90 | [self setNeedsDisplay]; 91 | } 92 | } 93 | 94 | 95 | - (void)setLineNumberBorderColor:(UIColor *)lineNumberBorderColor { 96 | if (![_lineNumberBorderColor isEqual:lineNumberBorderColor]) { 97 | _lineNumberBorderColor = lineNumberBorderColor; 98 | [self setNeedsDisplay]; 99 | } 100 | } 101 | 102 | 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /LineNumberTextView/LineNumberTextViewWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberTextViewWrapper.h 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LineNumberTextView.h" 11 | #import "LineNumberLayoutManager.h" 12 | 13 | // To use this from Swift, in the project settings, 14 | // set the Objective-C Bridging Header to include the path of this file. 15 | @interface LineNumberTextViewWrapper : UIView 16 | 17 | @property (nonatomic) LineNumberTextView* textView; 18 | 19 | /// Defaults to system font, 10pt. Convenience: just forwards to textView. 20 | @property (nonatomic) IBInspectable UIFont *lineNumberFont; 21 | 22 | /// Defaults to gray. Convenience: just forwards to textView. 23 | @property (nonatomic) IBInspectable UIColor *lineNumberBackgroundColor; 24 | 25 | /// Defaults to dark gray. Convenience: just forwards to textView. 26 | @property (nonatomic) IBInspectable UIColor *lineNumberBorderColor; 27 | 28 | /// Defaults to white. Convenience: just forwards to textView. 29 | @property (nonatomic) IBInspectable UIColor *lineNumberTextColor; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /LineNumberTextView/LineNumberTextViewWrapper.m: -------------------------------------------------------------------------------- 1 | // 2 | // LineNumberTextViewWrapper.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import "LineNumberTextViewWrapper.h" 10 | 11 | // 12 | // This class is here so that we can use a storyboard. This is required because we must use the UITextView's 13 | // -[initWithFrame:textContainer:] initializer in order to substitute our own layout manager. This cannot be done 14 | // using UITextView's -[initWithCoder:] initializer which is the one used whe views are created from a storyboard. 15 | // 16 | // This class also 17 | 18 | @implementation LineNumberTextViewWrapper 19 | 20 | - (id) initWithCoder:(NSCoder *)aDecoder { 21 | if ((self = [super initWithCoder:aDecoder])) { 22 | self.textView = [[LineNumberTextView alloc] initWithFrame:self.bounds]; 23 | self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 24 | [self addSubview:self.textView]; 25 | } 26 | return self; 27 | } 28 | 29 | - (UIFont *)lineNumberFont { 30 | return self.textView.lineNumberFont; 31 | } 32 | 33 | - (void)setLineNumberFont:(UIFont *)lineNumberFont { 34 | self.textView.lineNumberFont = lineNumberFont; 35 | } 36 | 37 | - (UIColor *)lineNumberBackgroundColor { 38 | return self.textView.lineNumberBackgroundColor; 39 | } 40 | 41 | - (void)setLineNumberBackgroundColor:(UIColor *)lineNumberBackgroundColor { 42 | self.textView.lineNumberBackgroundColor = lineNumberBackgroundColor; 43 | } 44 | 45 | - (UIColor *)lineNumberBorderColor { 46 | return self.textView.lineNumberBorderColor; 47 | } 48 | 49 | - (void)setLineNumberBorderColor:(UIColor *)lineNumberBorderColor { 50 | self.textView.lineNumberBorderColor = lineNumberBorderColor; 51 | } 52 | 53 | - (UIColor *)lineNumberTextColor { 54 | return self.textView.lineNumberTextColor; 55 | } 56 | 57 | - (void)setLineNumberTextColor:(UIColor *)lineNumberTextColor { 58 | self.textView.lineNumberTextColor = lineNumberTextColor; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextKit LineNumbers 2 | 3 | This sample code demonstrates one way of displaying line numbers in an iOS7 UITextView. This makes use of iOS7's Text Kit classes and can accommodate texts with varying fonts from one paragraph to another. 4 | 5 | The meat of the work takes place in the LineNumbersLayoutManager class (a subclass of NSLayoutManager). 6 | 7 | ![Screenshot](https://github.com/alldritt/TextKit_LineNumbers/blob/master/Screenshot.png?raw=true) 8 | 9 | This version has both an Objective-C and a Swift example. 10 | 11 | ## Performance 12 | 13 | I notice on my iPad 3 that there is a noticeable stuttering when scrolling the text downward the first time. I've spent some time profiling the code, and these delays seems to be happening within TextKit. My range-to-paragraph number calculation could be faster, but does not appear to be the most significant CPU user. 14 | 15 | If your application provides an efficient means of mapping character ranges to paragraph numbers, you can replace the -[LineNumbersLayoutManager __paraNumberForRange:] method with your own code. 16 | 17 | ## To Dos 18 | 19 | 1. The line number gutter width is fixed. It should probably expand as the total number of lines being displayed increases. Alternatively, the font size used to draw the line numbers could be reduced to make the line number text fit in the gutter space. 20 | 21 | 2. The line number text is centered vertically within the line fragments rect. I would like to align the line number text to the line fragment text's baseline, but I have not found a convenient way to determine this from the NSLayoutManager. 22 | 23 | 3. Find a better way of drawing the line number gutter background. Overriding UITextView's drawRect: seems like the wrong approach, but I've not found a viable alternative. 24 | 25 | ## License (MIT) 26 | 27 | Copyright (C) 2013 Mark Alldritt alldritt@latenightsw.com 28 | 29 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 30 | 31 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 32 | 33 | **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.** 34 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alldritt/TextKit_LineNumbers/59d242e4c7aae7e72568484dc31742308c519b3f/Screenshot.png -------------------------------------------------------------------------------- /TextKit_LineNumbers.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 63AEF2E41F8065BB00CC2F67 /* LineNumberLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63AEF2DF1F8065BB00CC2F67 /* LineNumberLayoutManager.m */; }; 11 | 63AEF2E51F8065BB00CC2F67 /* LineNumberTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63AEF2E11F8065BB00CC2F67 /* LineNumberTextView.m */; }; 12 | 63AEF2E61F8065BB00CC2F67 /* LineNumberTextViewWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 63AEF2E31F8065BB00CC2F67 /* LineNumberTextViewWrapper.m */; }; 13 | A54FEA7B1808FD7F004BD309 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A54FEA7A1808FD7F004BD309 /* Foundation.framework */; }; 14 | A54FEA7D1808FD7F004BD309 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A54FEA7C1808FD7F004BD309 /* CoreGraphics.framework */; }; 15 | A54FEA7F1808FD7F004BD309 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A54FEA7E1808FD7F004BD309 /* UIKit.framework */; }; 16 | A54FEA851808FD7F004BD309 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A54FEA831808FD7F004BD309 /* InfoPlist.strings */; }; 17 | A54FEA871808FD7F004BD309 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A54FEA861808FD7F004BD309 /* main.m */; }; 18 | A54FEA8B1808FD7F004BD309 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A54FEA8A1808FD7F004BD309 /* AppDelegate.m */; }; 19 | A54FEA8E1808FD7F004BD309 /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A54FEA8C1808FD7F004BD309 /* Main_iPhone.storyboard */; }; 20 | A54FEA911808FD7F004BD309 /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A54FEA8F1808FD7F004BD309 /* Main_iPad.storyboard */; }; 21 | A54FEA941808FD7F004BD309 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A54FEA931808FD7F004BD309 /* ViewController.m */; }; 22 | A54FEA961808FD7F004BD309 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A54FEA951808FD7F004BD309 /* Images.xcassets */; }; 23 | A54FEABD18090DB2004BD309 /* Sample.rtf in Resources */ = {isa = PBXBuildFile; fileRef = A54FEABC18090DB2004BD309 /* Sample.rtf */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 63AEF2DE1F8065BB00CC2F67 /* LineNumberLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberLayoutManager.h; sourceTree = ""; }; 28 | 63AEF2DF1F8065BB00CC2F67 /* LineNumberLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberLayoutManager.m; sourceTree = ""; }; 29 | 63AEF2E01F8065BB00CC2F67 /* LineNumberTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberTextView.h; sourceTree = ""; }; 30 | 63AEF2E11F8065BB00CC2F67 /* LineNumberTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberTextView.m; sourceTree = ""; }; 31 | 63AEF2E21F8065BB00CC2F67 /* LineNumberTextViewWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberTextViewWrapper.h; sourceTree = ""; }; 32 | 63AEF2E31F8065BB00CC2F67 /* LineNumberTextViewWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberTextViewWrapper.m; sourceTree = ""; }; 33 | A54FEA771808FD7F004BD309 /* TextKit_LineNumbers.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TextKit_LineNumbers.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | A54FEA7A1808FD7F004BD309 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 35 | A54FEA7C1808FD7F004BD309 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 36 | A54FEA7E1808FD7F004BD309 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 37 | A54FEA821808FD7F004BD309 /* TextKit_LineNumbers-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TextKit_LineNumbers-Info.plist"; sourceTree = ""; }; 38 | A54FEA841808FD7F004BD309 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 39 | A54FEA861808FD7F004BD309 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 40 | A54FEA881808FD7F004BD309 /* TextKit_LineNumbers-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TextKit_LineNumbers-Prefix.pch"; sourceTree = ""; }; 41 | A54FEA891808FD7F004BD309 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | A54FEA8A1808FD7F004BD309 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | A54FEA8D1808FD7F004BD309 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPhone.storyboard; sourceTree = ""; }; 44 | A54FEA901808FD7F004BD309 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; 45 | A54FEA921808FD7F004BD309 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 46 | A54FEA931808FD7F004BD309 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 47 | A54FEA951808FD7F004BD309 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 48 | A54FEA9C1808FD7F004BD309 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 49 | A54FEABC18090DB2004BD309 /* Sample.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Sample.rtf; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | A54FEA741808FD7F004BD309 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | A54FEA7D1808FD7F004BD309 /* CoreGraphics.framework in Frameworks */, 58 | A54FEA7F1808FD7F004BD309 /* UIKit.framework in Frameworks */, 59 | A54FEA7B1808FD7F004BD309 /* Foundation.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 63AEF2DD1F8065BB00CC2F67 /* LineNumberTextView */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 63AEF2DE1F8065BB00CC2F67 /* LineNumberLayoutManager.h */, 70 | 63AEF2DF1F8065BB00CC2F67 /* LineNumberLayoutManager.m */, 71 | 63AEF2E01F8065BB00CC2F67 /* LineNumberTextView.h */, 72 | 63AEF2E11F8065BB00CC2F67 /* LineNumberTextView.m */, 73 | 63AEF2E21F8065BB00CC2F67 /* LineNumberTextViewWrapper.h */, 74 | 63AEF2E31F8065BB00CC2F67 /* LineNumberTextViewWrapper.m */, 75 | ); 76 | name = LineNumberTextView; 77 | path = ../LineNumberTextView; 78 | sourceTree = ""; 79 | }; 80 | A54FEA6E1808FD7F004BD309 = { 81 | isa = PBXGroup; 82 | children = ( 83 | A54FEA801808FD7F004BD309 /* TextKit_LineNumbers */, 84 | A54FEA791808FD7F004BD309 /* Frameworks */, 85 | A54FEA781808FD7F004BD309 /* Products */, 86 | ); 87 | sourceTree = ""; 88 | }; 89 | A54FEA781808FD7F004BD309 /* Products */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | A54FEA771808FD7F004BD309 /* TextKit_LineNumbers.app */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | A54FEA791808FD7F004BD309 /* Frameworks */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | A54FEA7A1808FD7F004BD309 /* Foundation.framework */, 101 | A54FEA7C1808FD7F004BD309 /* CoreGraphics.framework */, 102 | A54FEA7E1808FD7F004BD309 /* UIKit.framework */, 103 | A54FEA9C1808FD7F004BD309 /* XCTest.framework */, 104 | ); 105 | name = Frameworks; 106 | sourceTree = ""; 107 | }; 108 | A54FEA801808FD7F004BD309 /* TextKit_LineNumbers */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | A54FEA8C1808FD7F004BD309 /* Main_iPhone.storyboard */, 112 | A54FEA8F1808FD7F004BD309 /* Main_iPad.storyboard */, 113 | A54FEA891808FD7F004BD309 /* AppDelegate.h */, 114 | A54FEA8A1808FD7F004BD309 /* AppDelegate.m */, 115 | A54FEA921808FD7F004BD309 /* ViewController.h */, 116 | A54FEA931808FD7F004BD309 /* ViewController.m */, 117 | A54FEABC18090DB2004BD309 /* Sample.rtf */, 118 | 63AEF2DD1F8065BB00CC2F67 /* LineNumberTextView */, 119 | A54FEA951808FD7F004BD309 /* Images.xcassets */, 120 | A54FEA811808FD7F004BD309 /* Supporting Files */, 121 | ); 122 | path = TextKit_LineNumbers; 123 | sourceTree = ""; 124 | }; 125 | A54FEA811808FD7F004BD309 /* Supporting Files */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | A54FEA821808FD7F004BD309 /* TextKit_LineNumbers-Info.plist */, 129 | A54FEA831808FD7F004BD309 /* InfoPlist.strings */, 130 | A54FEA861808FD7F004BD309 /* main.m */, 131 | A54FEA881808FD7F004BD309 /* TextKit_LineNumbers-Prefix.pch */, 132 | ); 133 | name = "Supporting Files"; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | A54FEA761808FD7F004BD309 /* TextKit_LineNumbers */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = A54FEAAC1808FD7F004BD309 /* Build configuration list for PBXNativeTarget "TextKit_LineNumbers" */; 142 | buildPhases = ( 143 | A54FEA731808FD7F004BD309 /* Sources */, 144 | A54FEA741808FD7F004BD309 /* Frameworks */, 145 | A54FEA751808FD7F004BD309 /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = TextKit_LineNumbers; 152 | productName = TextKit_LineNumbers; 153 | productReference = A54FEA771808FD7F004BD309 /* TextKit_LineNumbers.app */; 154 | productType = "com.apple.product-type.application"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | A54FEA6F1808FD7F004BD309 /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | LastUpgradeCheck = 0820; 163 | ORGANIZATIONNAME = "Late Night Software Ltd."; 164 | }; 165 | buildConfigurationList = A54FEA721808FD7F004BD309 /* Build configuration list for PBXProject "TextKit_LineNumbers" */; 166 | compatibilityVersion = "Xcode 3.2"; 167 | developmentRegion = English; 168 | hasScannedForEncodings = 0; 169 | knownRegions = ( 170 | en, 171 | Base, 172 | ); 173 | mainGroup = A54FEA6E1808FD7F004BD309; 174 | productRefGroup = A54FEA781808FD7F004BD309 /* Products */; 175 | projectDirPath = ""; 176 | projectRoot = ""; 177 | targets = ( 178 | A54FEA761808FD7F004BD309 /* TextKit_LineNumbers */, 179 | ); 180 | }; 181 | /* End PBXProject section */ 182 | 183 | /* Begin PBXResourcesBuildPhase section */ 184 | A54FEA751808FD7F004BD309 /* Resources */ = { 185 | isa = PBXResourcesBuildPhase; 186 | buildActionMask = 2147483647; 187 | files = ( 188 | A54FEA911808FD7F004BD309 /* Main_iPad.storyboard in Resources */, 189 | A54FEA961808FD7F004BD309 /* Images.xcassets in Resources */, 190 | A54FEA8E1808FD7F004BD309 /* Main_iPhone.storyboard in Resources */, 191 | A54FEABD18090DB2004BD309 /* Sample.rtf in Resources */, 192 | A54FEA851808FD7F004BD309 /* InfoPlist.strings in Resources */, 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXResourcesBuildPhase section */ 197 | 198 | /* Begin PBXSourcesBuildPhase section */ 199 | A54FEA731808FD7F004BD309 /* Sources */ = { 200 | isa = PBXSourcesBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | 63AEF2E61F8065BB00CC2F67 /* LineNumberTextViewWrapper.m in Sources */, 204 | A54FEA941808FD7F004BD309 /* ViewController.m in Sources */, 205 | 63AEF2E51F8065BB00CC2F67 /* LineNumberTextView.m in Sources */, 206 | A54FEA8B1808FD7F004BD309 /* AppDelegate.m in Sources */, 207 | 63AEF2E41F8065BB00CC2F67 /* LineNumberLayoutManager.m in Sources */, 208 | A54FEA871808FD7F004BD309 /* main.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | A54FEA831808FD7F004BD309 /* InfoPlist.strings */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | A54FEA841808FD7F004BD309 /* en */, 219 | ); 220 | name = InfoPlist.strings; 221 | sourceTree = ""; 222 | }; 223 | A54FEA8C1808FD7F004BD309 /* Main_iPhone.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | A54FEA8D1808FD7F004BD309 /* Base */, 227 | ); 228 | name = Main_iPhone.storyboard; 229 | sourceTree = ""; 230 | }; 231 | A54FEA8F1808FD7F004BD309 /* Main_iPad.storyboard */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | A54FEA901808FD7F004BD309 /* Base */, 235 | ); 236 | name = Main_iPad.storyboard; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXVariantGroup section */ 240 | 241 | /* Begin XCBuildConfiguration section */ 242 | A54FEAAA1808FD7F004BD309 /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 247 | CLANG_CXX_LIBRARY = "libc++"; 248 | CLANG_ENABLE_MODULES = YES; 249 | CLANG_ENABLE_OBJC_ARC = YES; 250 | CLANG_WARN_BOOL_CONVERSION = YES; 251 | CLANG_WARN_CONSTANT_CONVERSION = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INFINITE_RECURSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 259 | CLANG_WARN_UNREACHABLE_CODE = YES; 260 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 261 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 262 | COPY_PHASE_STRIP = NO; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | ENABLE_TESTABILITY = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu99; 266 | GCC_DYNAMIC_NO_PIC = NO; 267 | GCC_NO_COMMON_BLOCKS = YES; 268 | GCC_OPTIMIZATION_LEVEL = 0; 269 | GCC_PREPROCESSOR_DEFINITIONS = ( 270 | "DEBUG=1", 271 | "$(inherited)", 272 | ); 273 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 274 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 275 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 276 | GCC_WARN_UNDECLARED_SELECTOR = YES; 277 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 278 | GCC_WARN_UNUSED_FUNCTION = YES; 279 | GCC_WARN_UNUSED_VARIABLE = YES; 280 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 281 | ONLY_ACTIVE_ARCH = YES; 282 | SDKROOT = iphoneos; 283 | TARGETED_DEVICE_FAMILY = "1,2"; 284 | }; 285 | name = Debug; 286 | }; 287 | A54FEAAB1808FD7F004BD309 /* Release */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | ALWAYS_SEARCH_USER_PATHS = NO; 291 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 292 | CLANG_CXX_LIBRARY = "libc++"; 293 | CLANG_ENABLE_MODULES = YES; 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_WARN_BOOL_CONVERSION = YES; 296 | CLANG_WARN_CONSTANT_CONVERSION = YES; 297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 298 | CLANG_WARN_EMPTY_BODY = YES; 299 | CLANG_WARN_ENUM_CONVERSION = YES; 300 | CLANG_WARN_INFINITE_RECURSION = YES; 301 | CLANG_WARN_INT_CONVERSION = YES; 302 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 303 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 304 | CLANG_WARN_UNREACHABLE_CODE = YES; 305 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 306 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 307 | COPY_PHASE_STRIP = YES; 308 | ENABLE_NS_ASSERTIONS = NO; 309 | ENABLE_STRICT_OBJC_MSGSEND = YES; 310 | GCC_C_LANGUAGE_STANDARD = gnu99; 311 | GCC_NO_COMMON_BLOCKS = YES; 312 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 313 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 314 | GCC_WARN_UNDECLARED_SELECTOR = YES; 315 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 316 | GCC_WARN_UNUSED_FUNCTION = YES; 317 | GCC_WARN_UNUSED_VARIABLE = YES; 318 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 319 | SDKROOT = iphoneos; 320 | TARGETED_DEVICE_FAMILY = "1,2"; 321 | VALIDATE_PRODUCT = YES; 322 | }; 323 | name = Release; 324 | }; 325 | A54FEAAD1808FD7F004BD309 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 329 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 330 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 331 | GCC_PREFIX_HEADER = "TextKit_LineNumbers/TextKit_LineNumbers-Prefix.pch"; 332 | INFOPLIST_FILE = "TextKit_LineNumbers/TextKit_LineNumbers-Info.plist"; 333 | PRODUCT_BUNDLE_IDENTIFIER = "com.latenightsw.${PRODUCT_NAME:rfc1034identifier}"; 334 | PRODUCT_NAME = "$(TARGET_NAME)"; 335 | TARGETED_DEVICE_FAMILY = 2; 336 | WRAPPER_EXTENSION = app; 337 | }; 338 | name = Debug; 339 | }; 340 | A54FEAAE1808FD7F004BD309 /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 344 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 345 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 346 | GCC_PREFIX_HEADER = "TextKit_LineNumbers/TextKit_LineNumbers-Prefix.pch"; 347 | INFOPLIST_FILE = "TextKit_LineNumbers/TextKit_LineNumbers-Info.plist"; 348 | PRODUCT_BUNDLE_IDENTIFIER = "com.latenightsw.${PRODUCT_NAME:rfc1034identifier}"; 349 | PRODUCT_NAME = "$(TARGET_NAME)"; 350 | TARGETED_DEVICE_FAMILY = 2; 351 | WRAPPER_EXTENSION = app; 352 | }; 353 | name = Release; 354 | }; 355 | /* End XCBuildConfiguration section */ 356 | 357 | /* Begin XCConfigurationList section */ 358 | A54FEA721808FD7F004BD309 /* Build configuration list for PBXProject "TextKit_LineNumbers" */ = { 359 | isa = XCConfigurationList; 360 | buildConfigurations = ( 361 | A54FEAAA1808FD7F004BD309 /* Debug */, 362 | A54FEAAB1808FD7F004BD309 /* Release */, 363 | ); 364 | defaultConfigurationIsVisible = 0; 365 | defaultConfigurationName = Release; 366 | }; 367 | A54FEAAC1808FD7F004BD309 /* Build configuration list for PBXNativeTarget "TextKit_LineNumbers" */ = { 368 | isa = XCConfigurationList; 369 | buildConfigurations = ( 370 | A54FEAAD1808FD7F004BD309 /* Debug */, 371 | A54FEAAE1808FD7F004BD309 /* Release */, 372 | ); 373 | defaultConfigurationIsVisible = 0; 374 | defaultConfigurationName = Release; 375 | }; 376 | /* End XCConfigurationList section */ 377 | }; 378 | rootObject = A54FEA6F1808FD7F004BD309 /* Project object */; 379 | } 380 | -------------------------------------------------------------------------------- /TextKit_LineNumbers.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TextKit_LineNumbers.xcodeproj/xcuserdata/mall.xcuserdatad/xcschemes/TextKit_LineNumbers.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /TextKit_LineNumbers.xcodeproj/xcuserdata/mall.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TextKit_LineNumbers.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | A54FEA761808FD7F004BD309 16 | 17 | primary 18 | 19 | 20 | A54FEA9A1808FD7F004BD309 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // 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. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // 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. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/Base.lproj/Main_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/Base.lproj/Main_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /TextKit_LineNumbers/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 | } -------------------------------------------------------------------------------- /TextKit_LineNumbers/Sample.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 SourceCodePro-Regular;\f2\fmodern\fcharset0 Courier; 3 | } 4 | {\colortbl;\red255\green255\blue255;\red0\green116\blue0;\red100\green56\blue32;\red196\green26\blue22; 5 | \red170\green13\blue145;\red63\green110\blue116;\red46\green13\blue110;} 6 | \margl1440\margr1440\vieww12160\viewh12560\viewkind0 7 | \deftab720 8 | \pard\pardeftab720 9 | 10 | \f0\fs26 \cf0 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\ 11 | \ 12 | 13 | \f1 \cf2 \CocoaLigature0 //\cf0 \ 14 | \pard\tx528\pardeftab528\pardirnatural 15 | \cf2 // ViewController.m\cf0 \ 16 | \cf2 // TextKit_LineNumbers\cf0 \ 17 | \cf2 //\cf0 \ 18 | \cf2 // Created by Mark Alldritt on 2013-10-11.\cf0 \ 19 | \cf2 // Copyright (c) 2013 Late Night Software Ltd. All rights reserved.\cf0 \ 20 | \cf2 //\cf0 \ 21 | \ 22 | \cf3 #import \cf4 "ViewController.h"\cf3 \ 23 | \cf0 \ 24 | \cf5 @interface\cf0 \cf6 ViewController\cf0 ()\ 25 | \ 26 | \cf5 @end\cf0 \ 27 | \ 28 | \cf5 @implementation\cf0 ViewController\ 29 | \ 30 | - (\cf5 void\cf0 )viewDidLoad\ 31 | \{\ 32 | [\cf5 super\cf0 \cf7 viewDidLoad\cf0 ];\ 33 | \cf2 // Do any additional setup after loading the view, typically from a nib.\cf0 \ 34 | \}\ 35 | \ 36 | - (\cf5 void\cf0 )didReceiveMemoryWarning\ 37 | \{\ 38 | [\cf5 super\cf0 \cf7 didReceiveMemoryWarning\cf0 ];\ 39 | \cf2 // Dispose of any resources that can be recreated.\cf0 \ 40 | \}\ 41 | \ 42 | \cf5 @end\cf0 \ 43 | 44 | \fs22 \ 45 | \ 46 | \ 47 | This is a 48 | \fs28 test 49 | \fs22 of 50 | \fs36 multiple 51 | \fs22 font 52 | \fs48 sizes 53 | \fs22 within a 54 | \fs96 single 55 | \fs22 paragraph.\ 56 | \ 57 | \ 58 | \pard\pardeftab720 59 | 60 | \f2\fs26 \cf0 \CocoaLigature1 * A Project Gutenberg Canada Ebook *\ 61 | \ 62 | This ebook is made available at no cost and with very few\ 63 | restrictions. These restrictions apply only if (1) you make\ 64 | a change in the ebook (other than alteration for different\ 65 | display devices), or (2) you are making commercial use of\ 66 | the ebook. If either of these conditions applies, please\ 67 | check gutenberg.ca/links/licence.html before proceeding.\ 68 | \ 69 | This work is in the Canadian public domain, but may be under\ 70 | copyright in some countries. If you live outside Canada, check your\ 71 | country's copyright laws. IF THE BOOK IS UNDER COPYRIGHT\ 72 | IN YOUR COUNTRY, DO NOT DOWNLOAD OR REDISTRIBUTE THIS FILE.\ 73 | \ 74 | Title: The Adventures of the Chevalier De La Salle\ 75 | and his Companions, in their explorations of the\ 76 | prairies, forests, lakes, and rivers, of the New World,\ 77 | and their interviews with the savage tribes,\ 78 | two hundred years ago.\ 79 | Author: John Stevens Cabot Abbott (1805-1877)\ 80 | Date of first publication: 1875\ 81 | Place and date of edition used as base for this ebook:\ 82 | New York: Dodd, Mead & Company, 1875 (First Edition)\ 83 | Date first posted: 4 February 2008\ 84 | Date last updated: 4 February 2008\ 85 | Project Gutenberg Canada ebook #75\ 86 | \ 87 | This ebook was produced by: Mark C. Orton, Beth Trapaga\ 88 | & the Online Distributed Proofreading Team at http://www.pgdpcanada.net\ 89 | \ 90 | \ 91 | \ 92 | \ 93 | _AMERICAN PIONEERS AND PATRIOTS_.\ 94 | \ 95 | \ 96 | THE ADVENTURES OF THE CHEVALIER DE LA SALLE\ 97 | \ 98 | AND HIS COMPANIONS,\ 99 | \ 100 | IN THEIR EXPLORATIONS OF THE PRAIRIES, FORESTS, LAKES, AND RIVERS,\ 101 | \ 102 | OF THE NEW WORLD, AND THEIR INTERVIEWS WITH THE SAVAGE TRIBES,\ 103 | \ 104 | TWO HUNDRED YEARS AGO.\ 105 | \ 106 | \ 107 | \ 108 | By\ 109 | \ 110 | JOHN S. C. ABBOTT.\ 111 | \ 112 | \ 113 | \ 114 | NEW YORK:\ 115 | DODD, MEAD & COMPANY,\ 116 | Publishers\ 117 | \ 118 | Entered according to Act of Congress, in the year 1875, by\ 119 | DODD & MEAD,\ 120 | In the Office of the Librarian of Congress, at Washington.\ 121 | \ 122 | \ 123 | \ 124 | \ 125 | TO\ 126 | \ 127 | THE INHABITANTS OF THE GREAT VALLEY OF THE WEST,\ 128 | WHOSE MAGNIFICENT REALMS\ 129 | LA SALLE AND HIS COMPANIONS WERE THE FIRST TO EXPLORE,\ 130 | THIS VOLUME\ 131 | IS RESPECTFULLY DEDICATED, BY\ 132 | \ 133 | JOHN S. C. ABBOTT.\ 134 | \ 135 | \ 136 | \ 137 | \ 138 | PREFACE.\ 139 | \ 140 | \ 141 | There is no one of the Pioneers of this continent whose achievements\ 142 | equal those of the Chevalier Robert de la Salle. He passed over\ 143 | thousands of miles of lakes and rivers in the birch canoe. He traversed\ 144 | countless leagues of prairie and forest, on foot, guided by the\ 145 | moccasined Indian, threading trails which the white man's foot had\ 146 | never trod, and penetrating the villages and the wigwams of savages,\ 147 | where the white man's face had never been seen.\ 148 | \ 149 | Fear was an emotion La Salle never experienced. His adventures were\ 150 | more wild and wondrous than almost any recorded in the tales of\ 151 | chivalry. As time is rapidly obliterating from our land the footprints\ 152 | of the savage, it is important that these records of his strange\ 153 | existence should be perpetuated.\ 154 | \ 155 | Fortunately we have full and accurate accounts of these explorations,\ 156 | in the journals of Messrs. Marquette, Hennepin, and Joliet. We have\ 157 | still more minute narratives, in _Etablissement de la Foix_, par le P.\ 158 | Chretien Le Clercq, Paris 1691; _Dernieres D\'e8couvertes_, par le\ 159 | Chevalier de Tonti, Paris 1697; _Journal Historique_, par M. Joutel,\ 160 | Paris 1713.\ 161 | \ 162 | For the incidents in the last fatal expedition, to establish a colony\ 163 | at the mouth of the Mississippi, and the wonderful land tour of more\ 164 | than two thousand miles from the sea-coast of Texas to Quebec, through\ 165 | the territories of hundreds of tribes, we have the narratives of Father\ 166 | Christian Le Clercq, the narrative of Father Anastasias Douay, and the\ 167 | minute and admirably written almost daily journal of Monsieur Joutel,\ 168 | in his _Dernier Voyage_. Both Douay and Joutel accompanied this\ 169 | expedition from its commencement to its close.\ 170 | \ 171 | In these adventures the reader will find a more vivid description of\ 172 | the condition of this continent, and the character of its inhabitants\ 173 | two hundred years ago, than can be found anywhere else. Sir Walter\ 174 | Scott once remarked, that no one could take more pleasure in reading\ 175 | his romances, than he had taken in writing them. In this volume we have\ 176 | the romance of truth.\ 177 | \ 178 | If the writer can judge of the pleasure of the reader, from the intense\ 179 | interest he has experienced in following these adventurers through\ 180 | their perilous achievements, this narrative will prove to be one of\ 181 | extraordinary interest.\ 182 | \ 183 | JOHN S. C. ABBOTT.\ 184 | \ 185 | Fair Haven, Connecticut.\ 186 | } -------------------------------------------------------------------------------- /TextKit_LineNumbers/TextKit_LineNumbers-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 | UIMainStoryboardFile 28 | Main_iPhone 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/TextKit_LineNumbers-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 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LineNumberTextViewWrapper.h" 11 | 12 | 13 | @interface ViewController : UIViewController 14 | 15 | @property (assign, nonatomic) IBOutlet LineNumberTextViewWrapper* myView; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // Account for the transparent iOS7 sstatus bar 21 | NSUInteger navBarHeight = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame); 22 | UIEdgeInsets insets = self.myView.textView.contentInset; 23 | insets.top += navBarHeight; 24 | self.myView.textView.contentInset = insets; 25 | 26 | // Display some sample text to start with 27 | NSAttributedString* ats = [[NSAttributedString alloc] initWithFileURL:[NSBundle.mainBundle URLForResource:@"Sample" withExtension:@"rtf"] 28 | options:@{} 29 | documentAttributes:nil 30 | error:nil]; 31 | self.myView.textView.attributedText = ats; 32 | 33 | // Respond to software keyboard appearance and dissappearance as per: 34 | // http://stackoverflow.com/questions/26213681/ios-8-keyboard-hides-my-textview 35 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameDidChange:) name:UIKeyboardWillChangeFrameNotification object:nil]; 36 | } 37 | 38 | - (void)dealloc { 39 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 40 | } 41 | 42 | - (void)viewDidUnload { 43 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 44 | } 45 | 46 | - (void)keyboardFrameDidChange:(NSNotification *)notification 47 | { 48 | CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; 49 | CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; 50 | UIViewAnimationCurve animationCurve = [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]; 51 | NSTimeInterval animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] integerValue]; 52 | 53 | [UIView beginAnimations:nil context:nil]; 54 | [UIView setAnimationDuration:animationDuration]; 55 | [UIView setAnimationCurve:animationCurve]; 56 | 57 | CGRect newFrame = self.view.frame; 58 | CGRect keyboardFrameEnd = [self.view convertRect:keyboardEndFrame toView:nil]; 59 | CGRect keyboardFrameBegin = [self.view convertRect:keyboardBeginFrame toView:nil]; 60 | 61 | newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y); 62 | self.view.frame = newFrame; 63 | 64 | [UIView commitAnimations]; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /TextKit_LineNumbers/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TextKit_LineNumbers 4 | // 5 | // Created by Mark Alldritt on 2013-10-11. 6 | // Copyright (c) 2013 Late Night Software Ltd. 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 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 63AEF2F41F80670C00CC2F67 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63AEF2F31F80670C00CC2F67 /* AppDelegate.swift */; }; 11 | 63AEF2F61F80670C00CC2F67 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63AEF2F51F80670C00CC2F67 /* ViewController.swift */; }; 12 | 63AEF2F91F80670C00CC2F67 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63AEF2F71F80670C00CC2F67 /* Main.storyboard */; }; 13 | 63AEF2FB1F80670C00CC2F67 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63AEF2FA1F80670C00CC2F67 /* Assets.xcassets */; }; 14 | 63AEF2FE1F80670C00CC2F67 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63AEF2FC1F80670C00CC2F67 /* LaunchScreen.storyboard */; }; 15 | 63DA66331F806779001B4B50 /* LineNumberLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63DA662E1F806779001B4B50 /* LineNumberLayoutManager.m */; }; 16 | 63DA66341F806779001B4B50 /* LineNumberTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63DA66301F806779001B4B50 /* LineNumberTextView.m */; }; 17 | 63DA66351F806779001B4B50 /* LineNumberTextViewWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 63DA66321F806779001B4B50 /* LineNumberTextViewWrapper.m */; }; 18 | 63DA66371F806D6D001B4B50 /* Sample.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 63DA66361F806D6D001B4B50 /* Sample.rtf */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 63AEF2F01F80670C00CC2F67 /* TextKit_LineNumbers_swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TextKit_LineNumbers_swift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 63AEF2F31F80670C00CC2F67 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | 63AEF2F51F80670C00CC2F67 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | 63AEF2F81F80670C00CC2F67 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | 63AEF2FA1F80670C00CC2F67 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | 63AEF2FD1F80670C00CC2F67 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | 63AEF2FF1F80670C00CC2F67 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | 63DA662D1F806779001B4B50 /* LineNumberLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberLayoutManager.h; sourceTree = ""; }; 30 | 63DA662E1F806779001B4B50 /* LineNumberLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberLayoutManager.m; sourceTree = ""; }; 31 | 63DA66301F806779001B4B50 /* LineNumberTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberTextView.m; sourceTree = ""; }; 32 | 63DA66321F806779001B4B50 /* LineNumberTextViewWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineNumberTextViewWrapper.m; sourceTree = ""; }; 33 | 63DA66361F806D6D001B4B50 /* Sample.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = Sample.rtf; path = TextKit_LineNumbers/Sample.rtf; sourceTree = SOURCE_ROOT; }; 34 | 63DA66381F8070FC001B4B50 /* LineNumberTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberTextView.h; sourceTree = ""; }; 35 | 63DA66391F807109001B4B50 /* LineNumberTextViewWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineNumberTextViewWrapper.h; sourceTree = ""; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | 63AEF2ED1F80670C00CC2F67 /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 63AEF2E71F80670C00CC2F67 = { 50 | isa = PBXGroup; 51 | children = ( 52 | 63AEF2F21F80670C00CC2F67 /* TextKit_LineNumbers_swift */, 53 | 63AEF2F11F80670C00CC2F67 /* Products */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | 63AEF2F11F80670C00CC2F67 /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 63AEF2F01F80670C00CC2F67 /* TextKit_LineNumbers_swift.app */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | 63AEF2F21F80670C00CC2F67 /* TextKit_LineNumbers_swift */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 63AEF2F31F80670C00CC2F67 /* AppDelegate.swift */, 69 | 63AEF2F51F80670C00CC2F67 /* ViewController.swift */, 70 | 63DA662C1F806779001B4B50 /* LineNumberTextView */, 71 | 63AEF2F71F80670C00CC2F67 /* Main.storyboard */, 72 | 63DA66361F806D6D001B4B50 /* Sample.rtf */, 73 | 63AEF2FA1F80670C00CC2F67 /* Assets.xcassets */, 74 | 63AEF2FC1F80670C00CC2F67 /* LaunchScreen.storyboard */, 75 | 63AEF2FF1F80670C00CC2F67 /* Info.plist */, 76 | ); 77 | path = TextKit_LineNumbers_swift; 78 | sourceTree = ""; 79 | }; 80 | 63DA662C1F806779001B4B50 /* LineNumberTextView */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 63DA662D1F806779001B4B50 /* LineNumberLayoutManager.h */, 84 | 63DA662E1F806779001B4B50 /* LineNumberLayoutManager.m */, 85 | 63DA66381F8070FC001B4B50 /* LineNumberTextView.h */, 86 | 63DA66301F806779001B4B50 /* LineNumberTextView.m */, 87 | 63DA66391F807109001B4B50 /* LineNumberTextViewWrapper.h */, 88 | 63DA66321F806779001B4B50 /* LineNumberTextViewWrapper.m */, 89 | ); 90 | path = LineNumberTextView; 91 | sourceTree = SOURCE_ROOT; 92 | }; 93 | /* End PBXGroup section */ 94 | 95 | /* Begin PBXNativeTarget section */ 96 | 63AEF2EF1F80670C00CC2F67 /* TextKit_LineNumbers_swift */ = { 97 | isa = PBXNativeTarget; 98 | buildConfigurationList = 63AEF3021F80670C00CC2F67 /* Build configuration list for PBXNativeTarget "TextKit_LineNumbers_swift" */; 99 | buildPhases = ( 100 | 63AEF2EC1F80670C00CC2F67 /* Sources */, 101 | 63AEF2ED1F80670C00CC2F67 /* Frameworks */, 102 | 63AEF2EE1F80670C00CC2F67 /* Resources */, 103 | ); 104 | buildRules = ( 105 | ); 106 | dependencies = ( 107 | ); 108 | name = TextKit_LineNumbers_swift; 109 | productName = TextKit_LineNumbers_swift; 110 | productReference = 63AEF2F01F80670C00CC2F67 /* TextKit_LineNumbers_swift.app */; 111 | productType = "com.apple.product-type.application"; 112 | }; 113 | /* End PBXNativeTarget section */ 114 | 115 | /* Begin PBXProject section */ 116 | 63AEF2E81F80670C00CC2F67 /* Project object */ = { 117 | isa = PBXProject; 118 | attributes = { 119 | LastSwiftUpdateCheck = 0820; 120 | LastUpgradeCheck = 0820; 121 | ORGANIZATIONNAME = "David Phillip Oster"; 122 | TargetAttributes = { 123 | 63AEF2EF1F80670C00CC2F67 = { 124 | CreatedOnToolsVersion = 8.2.1; 125 | DevelopmentTeam = 2X3M9VFULE; 126 | ProvisioningStyle = Automatic; 127 | }; 128 | }; 129 | }; 130 | buildConfigurationList = 63AEF2EB1F80670C00CC2F67 /* Build configuration list for PBXProject "TextKit_LineNumbers_swift" */; 131 | compatibilityVersion = "Xcode 3.2"; 132 | developmentRegion = English; 133 | hasScannedForEncodings = 0; 134 | knownRegions = ( 135 | en, 136 | Base, 137 | ); 138 | mainGroup = 63AEF2E71F80670C00CC2F67; 139 | productRefGroup = 63AEF2F11F80670C00CC2F67 /* Products */; 140 | projectDirPath = ""; 141 | projectRoot = ""; 142 | targets = ( 143 | 63AEF2EF1F80670C00CC2F67 /* TextKit_LineNumbers_swift */, 144 | ); 145 | }; 146 | /* End PBXProject section */ 147 | 148 | /* Begin PBXResourcesBuildPhase section */ 149 | 63AEF2EE1F80670C00CC2F67 /* Resources */ = { 150 | isa = PBXResourcesBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 63AEF2FE1F80670C00CC2F67 /* LaunchScreen.storyboard in Resources */, 154 | 63AEF2FB1F80670C00CC2F67 /* Assets.xcassets in Resources */, 155 | 63DA66371F806D6D001B4B50 /* Sample.rtf in Resources */, 156 | 63AEF2F91F80670C00CC2F67 /* Main.storyboard in Resources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXResourcesBuildPhase section */ 161 | 162 | /* Begin PBXSourcesBuildPhase section */ 163 | 63AEF2EC1F80670C00CC2F67 /* Sources */ = { 164 | isa = PBXSourcesBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | 63DA66341F806779001B4B50 /* LineNumberTextView.m in Sources */, 168 | 63DA66351F806779001B4B50 /* LineNumberTextViewWrapper.m in Sources */, 169 | 63AEF2F61F80670C00CC2F67 /* ViewController.swift in Sources */, 170 | 63DA66331F806779001B4B50 /* LineNumberLayoutManager.m in Sources */, 171 | 63AEF2F41F80670C00CC2F67 /* AppDelegate.swift in Sources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXSourcesBuildPhase section */ 176 | 177 | /* Begin PBXVariantGroup section */ 178 | 63AEF2F71F80670C00CC2F67 /* Main.storyboard */ = { 179 | isa = PBXVariantGroup; 180 | children = ( 181 | 63AEF2F81F80670C00CC2F67 /* Base */, 182 | ); 183 | name = Main.storyboard; 184 | sourceTree = ""; 185 | }; 186 | 63AEF2FC1F80670C00CC2F67 /* LaunchScreen.storyboard */ = { 187 | isa = PBXVariantGroup; 188 | children = ( 189 | 63AEF2FD1F80670C00CC2F67 /* Base */, 190 | ); 191 | name = LaunchScreen.storyboard; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXVariantGroup section */ 195 | 196 | /* Begin XCBuildConfiguration section */ 197 | 63AEF3001F80670C00CC2F67 /* Debug */ = { 198 | isa = XCBuildConfiguration; 199 | buildSettings = { 200 | ALWAYS_SEARCH_USER_PATHS = NO; 201 | CLANG_ANALYZER_NONNULL = YES; 202 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 203 | CLANG_CXX_LIBRARY = "libc++"; 204 | CLANG_ENABLE_MODULES = YES; 205 | CLANG_ENABLE_OBJC_ARC = YES; 206 | CLANG_WARN_BOOL_CONVERSION = YES; 207 | CLANG_WARN_CONSTANT_CONVERSION = YES; 208 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 209 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 210 | CLANG_WARN_EMPTY_BODY = YES; 211 | CLANG_WARN_ENUM_CONVERSION = YES; 212 | CLANG_WARN_INFINITE_RECURSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 216 | CLANG_WARN_UNREACHABLE_CODE = YES; 217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 218 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 219 | COPY_PHASE_STRIP = NO; 220 | DEBUG_INFORMATION_FORMAT = dwarf; 221 | ENABLE_STRICT_OBJC_MSGSEND = YES; 222 | ENABLE_TESTABILITY = YES; 223 | GCC_C_LANGUAGE_STANDARD = gnu99; 224 | GCC_DYNAMIC_NO_PIC = NO; 225 | GCC_NO_COMMON_BLOCKS = YES; 226 | GCC_OPTIMIZATION_LEVEL = 0; 227 | GCC_PREPROCESSOR_DEFINITIONS = ( 228 | "DEBUG=1", 229 | "$(inherited)", 230 | ); 231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 233 | GCC_WARN_UNDECLARED_SELECTOR = YES; 234 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 235 | GCC_WARN_UNUSED_FUNCTION = YES; 236 | GCC_WARN_UNUSED_VARIABLE = YES; 237 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 238 | MTL_ENABLE_DEBUG_INFO = YES; 239 | ONLY_ACTIVE_ARCH = YES; 240 | SDKROOT = iphoneos; 241 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 242 | SWIFT_OBJC_BRIDGING_HEADER = LineNumberTextView/LineNumberTextViewWrapper.h; 243 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 244 | TARGETED_DEVICE_FAMILY = 2; 245 | }; 246 | name = Debug; 247 | }; 248 | 63AEF3011F80670C00CC2F67 /* Release */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ALWAYS_SEARCH_USER_PATHS = NO; 252 | CLANG_ANALYZER_NONNULL = YES; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_ENABLE_MODULES = YES; 256 | CLANG_ENABLE_OBJC_ARC = YES; 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_CONSTANT_CONVERSION = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 261 | CLANG_WARN_EMPTY_BODY = YES; 262 | CLANG_WARN_ENUM_CONVERSION = YES; 263 | CLANG_WARN_INFINITE_RECURSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 267 | CLANG_WARN_UNREACHABLE_CODE = YES; 268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 269 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 270 | COPY_PHASE_STRIP = NO; 271 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 272 | ENABLE_NS_ASSERTIONS = NO; 273 | ENABLE_STRICT_OBJC_MSGSEND = YES; 274 | GCC_C_LANGUAGE_STANDARD = gnu99; 275 | GCC_NO_COMMON_BLOCKS = YES; 276 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 277 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 278 | GCC_WARN_UNDECLARED_SELECTOR = YES; 279 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 280 | GCC_WARN_UNUSED_FUNCTION = YES; 281 | GCC_WARN_UNUSED_VARIABLE = YES; 282 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 283 | MTL_ENABLE_DEBUG_INFO = NO; 284 | SDKROOT = iphoneos; 285 | SWIFT_OBJC_BRIDGING_HEADER = LineNumberTextView/LineNumberTextViewWrapper.h; 286 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 287 | TARGETED_DEVICE_FAMILY = 2; 288 | VALIDATE_PRODUCT = YES; 289 | }; 290 | name = Release; 291 | }; 292 | 63AEF3031F80670C00CC2F67 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | DEVELOPMENT_TEAM = 2X3M9VFULE; 297 | INFOPLIST_FILE = TextKit_LineNumbers_swift/Info.plist; 298 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 299 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 300 | PRODUCT_BUNDLE_IDENTIFIER = "com.latenightsw.TextKit-LineNumbers"; 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | SWIFT_VERSION = 5.0; 303 | TARGETED_DEVICE_FAMILY = 1; 304 | }; 305 | name = Debug; 306 | }; 307 | 63AEF3041F80670C00CC2F67 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 311 | DEVELOPMENT_TEAM = 2X3M9VFULE; 312 | INFOPLIST_FILE = TextKit_LineNumbers_swift/Info.plist; 313 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 314 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 315 | PRODUCT_BUNDLE_IDENTIFIER = "com.latenightsw.TextKit-LineNumbers"; 316 | PRODUCT_NAME = "$(TARGET_NAME)"; 317 | SWIFT_VERSION = 5.0; 318 | TARGETED_DEVICE_FAMILY = 1; 319 | }; 320 | name = Release; 321 | }; 322 | /* End XCBuildConfiguration section */ 323 | 324 | /* Begin XCConfigurationList section */ 325 | 63AEF2EB1F80670C00CC2F67 /* Build configuration list for PBXProject "TextKit_LineNumbers_swift" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 63AEF3001F80670C00CC2F67 /* Debug */, 329 | 63AEF3011F80670C00CC2F67 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | 63AEF3021F80670C00CC2F67 /* Build configuration list for PBXNativeTarget "TextKit_LineNumbers_swift" */ = { 335 | isa = XCConfigurationList; 336 | buildConfigurations = ( 337 | 63AEF3031F80670C00CC2F67 /* Debug */, 338 | 63AEF3041F80670C00CC2F67 /* Release */, 339 | ); 340 | defaultConfigurationIsVisible = 0; 341 | defaultConfigurationName = Release; 342 | }; 343 | /* End XCConfigurationList section */ 344 | }; 345 | rootObject = 63AEF2E81F80670C00CC2F67 /* Project object */; 346 | } 347 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TextKit_LineNumbers_swift 4 | // 5 | // Copyright © 2017 David Phillip Oster. MIT License. 6 | // 7 | 8 | import UIKit 9 | 10 | @UIApplicationMain 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | var window: UIWindow? 13 | 14 | func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | // Override point for customization after application launch. 16 | return true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "ipad", 5 | "scale" : "1x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "ipad", 10 | "scale" : "2x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "ipad", 15 | "scale" : "1x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "scale" : "2x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "scale" : "1x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "scale" : "1x", 36 | "size" : "76x76" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "scale" : "2x", 41 | "size" : "76x76" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "2x", 46 | "size" : "83.5x83.5" 47 | }, 48 | { 49 | "idiom" : "ios-marketing", 50 | "scale" : "1x", 51 | "size" : "1024x1024" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations~ipad 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationPortraitUpsideDown 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /TextKit_LineNumbers_swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TextKit_LineNumbers_swift 4 | // 5 | // Copyright © 2017 David Phillip Oster. MIT License. 6 | // 7 | 8 | import UIKit 9 | 10 | class ViewController: UIViewController { 11 | @IBOutlet var wrapper: LineNumberTextViewWrapper! 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | do { 17 | // Display some sample text to start with 18 | let fileURL = Bundle.main.url(forResource: "Sample", withExtension: "rtf") 19 | let ats = try NSAttributedString(url: fileURL!, options: [:], documentAttributes: nil) 20 | wrapper.textView?.attributedText = ats 21 | } catch {} 22 | 23 | // Respond to software keyboard appearance and dissappearance as per: 24 | // http://stackoverflow.com/questions/26213681/ios-8-keyboard-hides-my-textview 25 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardFrameWillChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) 26 | } 27 | 28 | override func didReceiveMemoryWarning() { 29 | super.didReceiveMemoryWarning() 30 | // Dispose of any resources that can be recreated. 31 | } 32 | 33 | override func viewDidLayoutSubviews() { 34 | let viewBounds = view.bounds 35 | var wrapperFrame = viewBounds 36 | let topBarOffset = topLayoutGuide.length 37 | wrapperFrame.origin.y = topBarOffset 38 | wrapperFrame.size.height -= topBarOffset 39 | wrapper.frame = wrapperFrame 40 | } 41 | 42 | @objc func keyboardFrameWillChange(notification: NSNotification) { 43 | let keyboardEndFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue?)?.cgRectValue 44 | let keyboardBeginFrame = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue?)?.cgRectValue 45 | let animationCurve = (notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber?)?.intValue 46 | let animationDuration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber?)?.doubleValue 47 | 48 | UIView.animate(withDuration: animationDuration!, delay: 0, options: [UIView.AnimationOptions(rawValue: UInt(animationCurve!))], animations: { 49 | if let oldFrame = self.wrapper?.bounds { 50 | var newFrame = oldFrame 51 | let keyboardFrameBegin = self.view.convert(keyboardBeginFrame!, to: nil) 52 | let keyboardFrameEnd = self.view.convert(keyboardEndFrame!, from: nil) 53 | if keyboardFrameEnd.origin.y < keyboardFrameBegin.origin.y { 54 | newFrame.size.height -= max(0.0, keyboardFrameEnd.size.height) 55 | } 56 | self.wrapper.textView?.frame = newFrame 57 | } 58 | }, completion: nil) 59 | } 60 | } 61 | --------------------------------------------------------------------------------