Skip to content

Commit b3fe714

Browse files
committed
Performance improvements + various other tweaks.
1 parent 20b50ad commit b3fe714

File tree

6 files changed

+233
-33
lines changed

6 files changed

+233
-33
lines changed

SCXcodeMinimap.xcodeproj/project.pbxproj

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
188308091A7411830005DF40 /* DVTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVTKit.framework; path = ../../../../../Applications/Xcode.app/Contents/SharedFrameworks/DVTKit.framework; sourceTree = "<group>"; };
4848
1883080B1A7411930005DF40 /* IDESourceEditor.ideplugin */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = IDESourceEditor.ideplugin; path = ../../../../../Applications/Xcode.app/Contents/PlugIns/IDESourceEditor.ideplugin; sourceTree = "<group>"; };
4949
1883080F1A7411A70005DF40 /* IDESourceEditor */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = IDESourceEditor; path = ../../../../../Applications/Xcode.app/Contents/PlugIns/IDESourceEditor.ideplugin/Contents/MacOS/IDESourceEditor; sourceTree = "<group>"; };
50+
18C8F0331A7ECB1300C7A76F /* DVTFoldingLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTFoldingLayoutManager.h; sourceTree = "<group>"; };
51+
18C8F0341A7ECB1300C7A76F /* DVTLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTLayoutManager.h; sourceTree = "<group>"; };
5052
18FE09B21707639E00118FEB /* SCXcodeMinimap.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCXcodeMinimap.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; };
5153
18FE09B51707639E00118FEB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
5254
18FE09B81707639E00118FEB /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
@@ -81,8 +83,10 @@
8183
isa = PBXGroup;
8284
children = (
8385
184C11711A740F8A002A7C65 /* DVTCompletingTextView.h */,
86+
18C8F0331A7ECB1300C7A76F /* DVTFoldingLayoutManager.h */,
8487
184C11721A740F8A002A7C65 /* DVTFontAndColorTheme.h */,
8588
184C11731A740F8A002A7C65 /* DVTInvalidation-Protocol.h */,
89+
18C8F0341A7ECB1300C7A76F /* DVTLayoutManager.h */,
8690
184C11741A740F8A002A7C65 /* DVTPointerArray.h */,
8791
184C11751A740F8A002A7C65 /* DVTPreferenceSet-Protocol.h */,
8892
184C11761A740F8A002A7C65 /* DVTSourceLanguageSourceModelService.h */,
@@ -93,12 +97,12 @@
9397
184C117B1A740F8A002A7C65 /* DVTTextStorage.h */,
9498
184C117C1A740F8A002A7C65 /* DVTViewController.h */,
9599
184C117D1A740F8A002A7C65 /* IDEEditor.h */,
100+
1876135D1A77A69F00974BE1 /* IDEEditorDocument.h */,
101+
18FEFA8C1A782D8600DC98C5 /* IDEFileTextSettings.h */,
102+
1812C3911A77A7CF00E2CFB3 /* IDESourceCodeDocument.h */,
96103
184C117E1A740F8A002A7C65 /* IDESourceCodeEditor.h */,
97104
184C117F1A740F8A002A7C65 /* IDESourceCodeEditorContainerView.h */,
98105
184C11801A740F8A002A7C65 /* IDEViewController.h */,
99-
1876135D1A77A69F00974BE1 /* IDEEditorDocument.h */,
100-
1812C3911A77A7CF00E2CFB3 /* IDESourceCodeDocument.h */,
101-
18FEFA8C1A782D8600DC98C5 /* IDEFileTextSettings.h */,
102106
);
103107
path = "Xcode Headers";
104108
sourceTree = "<group>";

SCXcodeMinimap/SCXcodeMinimap-Info.plist

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
<string>1</string>
2525
<key>DVTPlugInCompatibilityUUIDs</key>
2626
<array>
27+
<string>FEC992CC-CA4A-4CFD-8881-77300FCB848A</string>
2728
<string>C4A681B0-4A26-480E-93EC-1218098B9AA0</string>
2829
<string>A2E4D43F-41F4-4FB9-BB94-7177011C9AED</string>
30+
<string>AD68E85B-441B-4301-B564-A45E4919A6AD</string>
2931
<string>63FC1C47-140D-42B0-BB4D-A10B2D225574</string>
3032
<string>37B30044-3B14-46BA-ABAA-F01000C27B63</string>
31-
<string>AD68E85B-441B-4301-B564-A45E4919A6AD</string>
32-
<string>FEC992CC-CA4A-4CFD-8881-77300FCB848A</string>
33+
<string>640F884E-CE55-4B40-87C0-8869546CAB7A</string>
3334
</array>
3435
<key>NSHumanReadableCopyright</key>
3536
<string>Copyright © 2013 Stefan Ceriu. All rights reserved.</string>

SCXcodeMinimap/SCXcodeMinimap.m

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@
1515

1616
const CGFloat kDefaultZoomLevel = 0.15f;
1717

18-
static char kAssociatedObjectMinimapViewKey;
19-
2018
static NSString * const IDESourceCodeEditorDidFinishSetupNotification = @"IDESourceCodeEditorDidFinishSetup";
21-
static NSString * const IDEEditorDocumentDidChangeNotification = @"IDEEditorDocumentDidChangeNotification";
22-
static NSString * const IDESourceCodeEditorTextViewBoundsDidChangeNotification = @"IDESourceCodeEditorTextViewBoundsDidChangeNotification";
2319

2420
NSString * const SCXodeMinimapShowNotification = @"SCXodeMinimapShowNotification";
2521
NSString * const SCXodeMinimapHideNotification = @"SCXodeMinimapHideNotification";
@@ -44,7 +40,6 @@ - (id)init
4440
[self createMenuItem];
4541

4642
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDidFinishSetup:) name:IDESourceCodeEditorDidFinishSetupNotification object:nil];
47-
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCodeEditorBoundsChange:) name:IDESourceCodeEditorTextViewBoundsDidChangeNotification object:nil];
4843
}
4944
return self;
5045
}
@@ -101,18 +96,6 @@ - (void)showMiniMap:(NSMenuItem *)sender
10196

10297
#pragma mark - Xcode Notification
10398

104-
- (void)onCodeEditorBoundsChange:(NSNotification*)sender
105-
{
106-
if(![sender.object isKindOfClass:[IDESourceCodeEditor class]]) {
107-
NSLog(@"Could not fetch source code editor container");
108-
return;
109-
}
110-
111-
IDESourceCodeEditor *editor = (IDESourceCodeEditor *)[sender object];
112-
SCXcodeMinimapView *miniMapView = objc_getAssociatedObject(editor.scrollView, &kAssociatedObjectMinimapViewKey);
113-
[miniMapView updateOffset];
114-
}
115-
11699
- (void)onDidFinishSetup:(NSNotification*)sender
117100
{
118101
if(![sender.object isKindOfClass:[IDESourceCodeEditor class]]) {
@@ -129,8 +112,6 @@ - (void)onDidFinishSetup:(NSNotification*)sender
129112
SCXcodeMinimapView *miniMapView = [[SCXcodeMinimapView alloc] initWithFrame:miniMapScrollViewFrame editor:editor];
130113
[editor.containerView addSubview:miniMapView];
131114

132-
objc_setAssociatedObject(editor.scrollView, &kAssociatedObjectMinimapViewKey, miniMapView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
133-
134115
[miniMapView setVisible:![[NSUserDefaults standardUserDefaults] boolForKey:SCXodeMinimapIsInitiallyHidden]];
135116
}
136117

SCXcodeMinimap/SCXcodeMinimapView.m

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
#import "SCXcodeMinimapSelectionView.h"
1212

1313
#import "IDESourceCodeEditor.h"
14+
1415
#import "DVTTextStorage.h"
16+
#import "DVTLayoutManager.h"
17+
1518
#import "DVTPointerArray.h"
1619
#import "DVTSourceTextView.h"
1720
#import "DVTSourceNodeTypes.h"
@@ -25,16 +28,35 @@
2528
static NSString * const kXcodeSyntaxCommentDocKeywordNodeName = @"xcode.syntax.comment.doc.keyword";
2629
static NSString * const kXcodeSyntaxPreprocessorNodeName = @"xcode.syntax.preprocessor";
2730

31+
static NSString * const IDEEditorDocumentDidChangeNotification = @"IDEEditorDocumentDidChangeNotification";
32+
static NSString * const IDESourceCodeEditorTextViewBoundsDidChangeNotification = @"IDESourceCodeEditorTextViewBoundsDidChangeNotification";
2833
static NSString * const DVTFontAndColorSourceTextSettingsChangedNotification = @"DVTFontAndColorSourceTextSettingsChangedNotification";
2934

35+
36+
@interface NSObject (SCXcodeMinimapDelayedLayoutManager)
37+
38+
- (void)sc_performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay cancelPreviousRequest:(BOOL)cancel;
39+
40+
@end
41+
42+
43+
@interface SCXcodeMinimapDelayedLayoutManager : DVTLayoutManager
44+
45+
@property (nonatomic, strong) NSValue *combinedRangeValue;
46+
47+
@end
48+
49+
3050
@interface SCXcodeMinimapView () <NSLayoutManagerDelegate>
3151

52+
@property (nonatomic, strong) IDESourceCodeEditor *editor;
3253
@property (nonatomic, strong) NSScrollView *editorScrollView;
3354
@property (nonatomic, strong) DVTSourceTextView *editorTextView;
3455

3556
@property (nonatomic, strong) NSScrollView *scrollView;
3657
@property (nonatomic, strong) DVTSourceTextView *textView;
3758
@property (nonatomic, strong) SCXcodeMinimapSelectionView *selectionView;
59+
@property (nonatomic, strong) IDESourceCodeDocument *document;
3860

3961
@end
4062

@@ -49,12 +71,15 @@ - (instancetype)initWithFrame:(NSRect)frame editor:(IDESourceCodeEditor *)editor
4971
{
5072
if (self = [super initWithFrame:frame])
5173
{
74+
self.editor = editor;
5275
self.editorScrollView = editor.scrollView;
5376
self.editorTextView = editor.textView;
5477

78+
5579
[self setWantsLayer:YES];
5680
[self setAutoresizingMask:NSViewMinXMargin | NSViewHeightSizable];
5781

82+
5883
self.scrollView = [[NSScrollView alloc] initWithFrame:self.bounds];
5984
[self.scrollView setAutoresizingMask:NSViewMinXMargin | NSViewHeightSizable];
6085
[self.scrollView setDrawsBackground:NO];
@@ -64,32 +89,45 @@ - (instancetype)initWithFrame:(NSRect)frame editor:(IDESourceCodeEditor *)editor
6489
[self addSubview:self.scrollView];
6590

6691
self.textView = [[DVTSourceTextView alloc] initWithFrame:self.editorTextView.bounds];
67-
[self.textView setTextStorage:editor.textView.textStorage];
92+
SCXcodeMinimapDelayedLayoutManager *layoutManager = [[SCXcodeMinimapDelayedLayoutManager alloc] init];
93+
[self.textView.textContainer replaceLayoutManager:layoutManager];
6894
[self.textView setEditable:NO];
6995
[self.textView setSelectable:NO];
7096

97+
[self.editorTextView.textStorage addLayoutManager:layoutManager];
98+
7199
[self.scrollView setDocumentView:self.textView];
72100

101+
[self.scrollView setAllowsMagnification:YES];
102+
[self.scrollView setMinMagnification:kDefaultZoomLevel];
103+
[self.scrollView setMagnification:kDefaultZoomLevel];
104+
105+
73106
self.selectionView = [[SCXcodeMinimapSelectionView alloc] init];
74107
[self.textView addSubview:_selectionView];
75108

109+
76110
[self updateTheme];
77111

112+
113+
__weak typeof(self) weakSelf = self;
78114
[[NSNotificationCenter defaultCenter] addObserverForName:SCXodeMinimapShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
79-
[self setVisible:YES];
115+
[weakSelf setVisible:YES];
80116
}];
81117

82118
[[NSNotificationCenter defaultCenter] addObserverForName:SCXodeMinimapHideNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
83-
[self setVisible:NO];
119+
[weakSelf setVisible:NO];
84120
}];
85121

86122
[[NSNotificationCenter defaultCenter] addObserverForName:DVTFontAndColorSourceTextSettingsChangedNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
87-
[self updateTheme];
123+
[weakSelf updateTheme];
88124
}];
89125

90-
[self.scrollView setAllowsMagnification:YES];
91-
[self.scrollView setMinMagnification:kDefaultZoomLevel];
92-
[self.scrollView setMagnification:kDefaultZoomLevel];
126+
[[NSNotificationCenter defaultCenter] addObserverForName:IDESourceCodeEditorTextViewBoundsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
127+
if([note.object isEqual:weakSelf.editor]) {
128+
[self updateOffset];
129+
}
130+
}];
93131
}
94132

95133
return self;
@@ -111,12 +149,17 @@ - (void)setVisible:(BOOL)visible
111149

112150
// Ensure the layout manager's delegate is set to self. The DVTSourceTextView resets it if called to early.
113151
[self.textView.layoutManager setDelegate:self];
152+
[self.textView.layoutManager setAllowsNonContiguousLayout:NO];
114153
}
115154

116155
#pragma mark - NSLayoutManagerDelegate
117156

118157
- (NSDictionary *)layoutManager:(NSLayoutManager *)layoutManager shouldUseTemporaryAttributes:(NSDictionary *)attrs forDrawingToScreen:(BOOL)toScreen atCharacterIndex:(NSUInteger)charIndex effectiveRange:(NSRangePointer)effectiveCharRange
119158
{
159+
if(!toScreen || self.hidden) {
160+
return nil;
161+
}
162+
120163
DVTTextStorage *storage = [self.editorTextView textStorage];
121164

122165
short currentNodeId = [storage nodeTypeAtCharacterIndex:charIndex effectiveRange:effectiveCharRange context:nil];
@@ -151,7 +194,6 @@ - (void)layoutManager:(NSLayoutManager *)layoutManager didCompleteLayoutForTextC
151194
}
152195
}
153196

154-
155197
#pragma mark - Navigation
156198

157199
- (void)updateOffset
@@ -165,7 +207,6 @@ - (void)updateOffset
165207
NSRect selectionViewFrame = NSMakeRect(0, 0, self.bounds.size.width * (1 / self.scrollView.magnification), self.editorScrollView.visibleRect.size.height);
166208

167209
if(editorContentHeight == 0.0f) {
168-
NSLog(@"editorContentHeight IS %f", editorContentHeight);
169210
[self.selectionView setFrame:selectionViewFrame];
170211
return;
171212
}
@@ -234,3 +275,75 @@ - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
234275
}
235276

236277
@end
278+
279+
280+
@implementation SCXcodeMinimapDelayedLayoutManager
281+
282+
- (void)delayedAddOperation:(NSOperation *)operation {
283+
[[NSOperationQueue currentQueue] addOperation:operation];
284+
}
285+
286+
- (void)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
287+
[self performSelector:@selector(delayedAddOperation:)
288+
withObject:[NSBlockOperation blockOperationWithBlock:block]
289+
afterDelay:delay];
290+
}
291+
292+
- (void)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay cancelPreviousRequest:(BOOL)cancel {
293+
if (cancel) {
294+
[NSObject cancelPreviousPerformRequestsWithTarget:self];
295+
}
296+
[self performBlock:block afterDelay:delay];
297+
}
298+
299+
- (void)invalidateDisplayForCharacterRange:(NSRange)charRange
300+
{
301+
if(self.combinedRangeValue) {
302+
self.combinedRangeValue = [NSValue valueWithRange:NSUnionRange(self.combinedRangeValue.rangeValue, charRange)];
303+
} else {
304+
self.combinedRangeValue = [NSValue valueWithRange:charRange];
305+
}
306+
307+
[self performBlock:^{
308+
309+
NSRange range = NSIntersectionRange(self.combinedRangeValue.rangeValue, NSMakeRange(0, self.textStorage.length));
310+
[super invalidateDisplayForCharacterRange:range];
311+
self.combinedRangeValue = nil;
312+
} afterDelay:0.5f cancelPreviousRequest:YES];
313+
}
314+
315+
- (void)_invalidateLayoutForExtendedCharacterRange:(NSRange)charRange isSoft:(BOOL)isSoft
316+
{
317+
if(isSoft) {
318+
[super _invalidateLayoutForExtendedCharacterRange:charRange isSoft:isSoft];
319+
}
320+
}
321+
322+
- (void)textStorage:(id)arg1 edited:(unsigned long long)arg2 range:(struct _NSRange)arg3 changeInLength:(long long)arg4 invalidatedRange:(struct _NSRange)arg5
323+
{
324+
325+
}
326+
327+
@end
328+
329+
330+
@implementation NSObject (SCXcodeMinimapDelayedLayoutManager)
331+
332+
- (void)sc_performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
333+
[self performSelector:@selector(delayedAddOperation:)
334+
withObject:[NSBlockOperation blockOperationWithBlock:block]
335+
afterDelay:delay];
336+
}
337+
338+
- (void)sc_performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay cancelPreviousRequest:(BOOL)cancel {
339+
if (cancel) {
340+
[NSObject cancelPreviousPerformRequestsWithTarget:self];
341+
}
342+
[self sc_performBlock:block afterDelay:delay];
343+
}
344+
345+
- (void)sc_delayedAddOperation:(NSOperation *)operation {
346+
[[NSOperationQueue currentQueue] addOperation:operation];
347+
}
348+
349+
@end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Generated by class-dump 3.3.4 (64 bit).
3+
*
4+
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2011 by Steve Nygard.
5+
*/
6+
7+
#import <AppKit/NSLayoutManager.h>
8+
9+
@class DVTFoldingManager, DVTTextFoldInlineTokenAttachmentCell, NSCell;
10+
11+
@interface DVTFoldingLayoutManager : NSLayoutManager
12+
{
13+
DVTFoldingManager *_foldingManager;
14+
NSCell *_blockFoldCell;
15+
DVTTextFoldInlineTokenAttachmentCell *_inlineFoldCell;
16+
}
17+
18+
+ (id)layoutLogAspect;
19+
@property(copy) DVTTextFoldInlineTokenAttachmentCell *inlineFoldCell; // @synthesize inlineFoldCell=_inlineFoldCell;
20+
@property(copy) NSCell *blockFoldCell; // @synthesize blockFoldCell=_blockFoldCell;
21+
@property(readonly) DVTFoldingManager *foldingManager; // @synthesize foldingManager=_foldingManager;
22+
- (unsigned long long)characterIndexForPoint:(struct CGPoint)arg1 inTextContainer:(id)arg2 fractionOfDistanceBetweenInsertionPoints:(double *)arg3;
23+
- (id)foldCellAtCharacterIndex:(unsigned long long)arg1;
24+
- (struct CGSize)attachmentSizeForGlyphAtIndex:(unsigned long long)arg1;
25+
- (void)drawGlyphsForGlyphRange:(struct _NSRange)arg1 atPoint:(struct CGPoint)arg2;
26+
- (void)foldingManager:(id)arg1 didUnfoldRange:(struct _NSRange)arg2;
27+
- (void)foldingManager:(id)arg1 didFoldRange:(struct _NSRange)arg2;
28+
- (void)_invalidateGlyphsInCharacterRange:(struct _NSRange)arg1;
29+
- (struct _NSRange)_paragraphExtendedCharacterRange:(struct _NSRange)arg1;
30+
- (void)textStorage:(id)arg1 edited:(unsigned long long)arg2 range:(struct _NSRange)arg3 changeInLength:(long long)arg4 invalidatedRange:(struct _NSRange)arg5;
31+
- (void)_invalidateGlyphsForExtendedCharacterRange:(struct _NSRange)arg1 changeInLength:(long long)arg2 includeBlocks:(BOOL)arg3;
32+
- (struct _NSRange)_extendedCharRangeForInvalidation:(struct _NSRange)arg1 editedCharRange:(struct _NSRange)arg2;
33+
- (void)generateInlineFoldsForCharacterRange:(struct _NSRange)arg1;
34+
- (struct _NSRange)paragraphRangeForLineRange:(struct _NSRange)arg1;
35+
- (struct CGSize)layoutSizeForFoldAtCharacterIndex:(unsigned long long)arg1;
36+
- (BOOL)foldsAreValid:(id)arg1;
37+
- (void)setTextStorage:(id)arg1;
38+
- (void)enableTextFolding:(BOOL)arg1;
39+
- (id)textStorage;
40+
41+
@end

0 commit comments

Comments
 (0)