Skip to content

Commit a0d7b21

Browse files
committed
Merge branch 'develop'; Version 2.1.0
2 parents f250fac + 2796e59 commit a0d7b21

21 files changed

+1147
-153
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
## Changelog
22

3+
#### 2.1.0 - 2014/06/04
4+
**An update with new features, improvements and bugfixes, including:**
5+
6+
* Preliminary support for Xcode 6 and Swift
7+
* Correct Word Order by two-pass matching, useful when:
8+
you don't remember the order (eg rangemake)
9+
want to narrow down without backspacing (eg nsexceptioninvalid)
10+
* Correct Letter Case by replacing with exact match if there is only one
11+
* Option to hide cursor when inline preview shows a non-prefix match
12+
* Keep the selection when narrowing the search (unless it was the best match)
13+
* Better inline previews, including token text, just without tokens
14+
* Improved range convertions and highlighting
15+
* Fixed useful prefix underlining when it spans multiple segments
16+
* Fixed completion list positioning
17+
318
#### 2.0.1 - 2014/04/25
419
**A minor update with small bugfixes and improvements, including:**
520

FuzzyAutocomplete.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
58C3C25118110DB70031D9CD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58C3C24F18110DB70031D9CD /* InfoPlist.strings */; };
1515
58C3C25A181128140031D9CD /* FuzzyAutocomplete.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C3C259181128140031D9CD /* FuzzyAutocomplete.m */; };
1616
58E9F98F1813A0FE000928AF /* IDEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58E9F98E1813A0FE000928AF /* IDEKit.framework */; };
17+
650C2FA6190B31600021BCD8 /* FAMatchPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 650C2FA5190B31600021BCD8 /* FAMatchPattern.m */; };
1718
650D4F5F18E5FCFF00F5DBEE /* FASettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 650D4F5E18E5FCFF00F5DBEE /* FASettings.m */; };
1819
65346CC7189D885C004EB7BE /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C3C24B18110DB70031D9CD /* AppKit.framework */; };
1920
6540232C18F9F79700D580B3 /* FAItemScoringMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 6540232B18F9F79700D580B3 /* FAItemScoringMethod.m */; };
@@ -52,6 +53,10 @@
5253
58E391E7181289A100C18DBF /* IDEIndexCompletionItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IDEIndexCompletionItem.h; sourceTree = "<group>"; };
5354
58E9F98D18139EC5000928AF /* IDEOpenQuicklyPattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IDEOpenQuicklyPattern.h; sourceTree = "<group>"; };
5455
58E9F98E1813A0FE000928AF /* IDEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDEKit.framework; path = ../../../../Applications/Xcode.app/Contents/Frameworks/IDEKit.framework; sourceTree = "<group>"; };
56+
6503E741190AB08D00017267 /* DVTTextStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DVTTextStorage.h; sourceTree = "<group>"; };
57+
6503E742190AB08D00017267 /* DVTTextStorageDelegate-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DVTTextStorageDelegate-Protocol.h"; sourceTree = "<group>"; };
58+
650C2FA4190B31600021BCD8 /* FAMatchPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FAMatchPattern.h; sourceTree = "<group>"; };
59+
650C2FA5190B31600021BCD8 /* FAMatchPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FAMatchPattern.m; sourceTree = "<group>"; };
5560
650D4F5D18E5FCFF00F5DBEE /* FASettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FASettings.h; sourceTree = "<group>"; };
5661
650D4F5E18E5FCFF00F5DBEE /* FASettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FASettings.m; sourceTree = "<group>"; };
5762
6540232A18F9F79700D580B3 /* FAItemScoringMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FAItemScoringMethod.h; sourceTree = "<group>"; };
@@ -66,7 +71,10 @@
6671
658A7C8218A13279007655E0 /* DVTPreferenceSet-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DVTPreferenceSet-Protocol.h"; sourceTree = "<group>"; };
6772
65A066A318F2CE4600B15293 /* FASettingsWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FASettingsWindow.xib; sourceTree = "<group>"; };
6873
65AA753518F367360057D0A7 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
74+
65C8108D193FA29500CE8D9E /* DVTCompletingTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DVTCompletingTextView.h; sourceTree = "<group>"; };
6975
65DB740C18A12FBF001CDD83 /* DVTFontAndColorTheme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DVTFontAndColorTheme.h; sourceTree = "<group>"; };
76+
65E3D500190AAD8400A42F56 /* DVTCompletingTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DVTCompletingTextView.h; sourceTree = "<group>"; };
77+
65E3D501190AADAB00A42F56 /* DVTCompletingTextViewDelegate-Protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DVTCompletingTextViewDelegate-Protocol.h"; sourceTree = "<group>"; };
7078
65E6847218F897400093A671 /* NSBundle+LSLProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+LSLProperties.h"; sourceTree = "<group>"; };
7179
65E6847318F897400093A671 /* NSBundle+LSLProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+LSLProperties.m"; sourceTree = "<group>"; };
7280
65EAE5DC18ECADF900F0974C /* FATheme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FATheme.h; sourceTree = "<group>"; };
@@ -92,11 +100,16 @@
92100
580BC1E5181172D100D53F1F /* Xcode Headers */ = {
93101
isa = PBXGroup;
94102
children = (
103+
6503E741190AB08D00017267 /* DVTTextStorage.h */,
104+
6503E742190AB08D00017267 /* DVTTextStorageDelegate-Protocol.h */,
95105
58BA07C018124BFC0070060D /* DVTInvalidation-Protocol.h */,
106+
65C8108D193FA29500CE8D9E /* DVTCompletingTextView.h */,
96107
58BA07C118124C0A0070060D /* DVTTextCompletionDataSourceDelegate-Protocol.h */,
97108
58DA96F21813D38A00D0082B /* DVTTextCompletionInlinePreviewController.h */,
98109
58DA96F31813D48D00D0082B /* DVTTextCompletionItem-Protocol.h */,
99110
5870150918140BB700082A37 /* DVTTextCompletionListWindowController.h */,
111+
65E3D501190AADAB00A42F56 /* DVTCompletingTextViewDelegate-Protocol.h */,
112+
65E3D500190AAD8400A42F56 /* DVTCompletingTextView.h */,
100113
58BA07BF18124BD50070060D /* DVTTextCompletionSession.h */,
101114
58E391E7181289A100C18DBF /* IDEIndexCompletionItem.h */,
102115
58E9F98D18139EC5000928AF /* IDEOpenQuicklyPattern.h */,
@@ -169,6 +182,8 @@
169182
65599234189FFFD600C44208 /* DVTTextCompletionInlinePreviewController+FuzzyAutocomplete.m */,
170183
655738C618F47F1E003FD40A /* FATextCompletionListHeaderView.h */,
171184
655738C718F47F1E003FD40A /* FATextCompletionListHeaderView.m */,
185+
650C2FA4190B31600021BCD8 /* FAMatchPattern.h */,
186+
650C2FA5190B31600021BCD8 /* FAMatchPattern.m */,
172187
);
173188
path = FuzzyAutocomplete;
174189
sourceTree = "<group>";
@@ -265,6 +280,7 @@
265280
6540232C18F9F79700D580B3 /* FAItemScoringMethod.m in Sources */,
266281
58501C0618165B0600AA3179 /* JRSwizzle.m in Sources */,
267282
58C3C25A181128140031D9CD /* FuzzyAutocomplete.m in Sources */,
283+
650C2FA6190B31600021BCD8 /* FAMatchPattern.m in Sources */,
268284
650D4F5F18E5FCFF00F5DBEE /* FASettings.m in Sources */,
269285
65EAE5DE18ECADF900F0974C /* FATheme.m in Sources */,
270286
657EB240189D76DC00B04AC0 /* DVTTextCompletionListWindowController+FuzzyAutocomplete.m in Sources */,

FuzzyAutocomplete/DVTTextCompletionInlinePreviewController+FuzzyAutocomplete.m

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@
1010
#import "DVTTextCompletionSession.h"
1111
#import "DVTTextCompletionSession+FuzzyAutocomplete.h"
1212
#import "DVTFontAndColorTheme.h"
13+
#import "FASettings.h"
1314
#import "JRSwizzle.h"
1415
#import <objc/runtime.h>
1516

17+
// A helper class that ensures completionText does not contain tokens.
18+
// Otherwise the cursor can be possibly placed inside a token.
19+
@interface FAPreviewItem : NSObject <DVTTextCompletionItem>
20+
+ (instancetype) previewItemForItem: (id<DVTTextCompletionItem>) item;
21+
@end
22+
1623
@implementation DVTTextCompletionInlinePreviewController (FuzzyAutocomplete)
1724

1825
+ (void) fa_swizzleMethods {
@@ -23,17 +30,34 @@ + (void) fa_swizzleMethods {
2330
[self jr_swizzleMethod: @selector(_showPreviewForItem:)
2431
withMethod: @selector(_fa_showPreviewForItem:)
2532
error: NULL];
33+
34+
[self jr_swizzleMethod: @selector(hideInlinePreviewWithReason:)
35+
withMethod: @selector(_fa_hideInlinePreviewWithReason:)
36+
error: nil];
2637
}
2738

2839
#pragma mark - overrides
2940

41+
- (void)_fa_hideInlinePreviewWithReason: (int) reason {
42+
DVTTextCompletionSession * session = [self valueForKey: @"_session"];
43+
NSTextView * textView = (NSTextView *) session.textView;
44+
textView.insertionPointColor = [textView.insertionPointColor colorWithAlphaComponent: 1];
45+
[self _fa_hideInlinePreviewWithReason: reason];
46+
}
47+
3048
// We added calculation of matchedRanges and ghostRange here.
3149
- (void) _fa_showPreviewForItem: (id<DVTTextCompletionItem>) item {
50+
item = [FAPreviewItem previewItemForItem: item];
51+
3252
[self _fa_showPreviewForItem: item];
3353

3454
DVTTextCompletionSession * session = [self valueForKey: @"_session"];
3555

3656
NSArray * ranges = [session fa_matchedRangesForItem: item];
57+
ranges = [ranges arrayByAddingObjectsFromArray: [session fa_secondPassMatchedRangesForItem: item]];
58+
ranges = [ranges sortedArrayUsingComparator:^NSComparisonResult(NSValue * v1, NSValue * v2) {
59+
return [@(v1.rangeValue.location) compare: @(v2.rangeValue.location)];
60+
}];
3761

3862
if (!ranges.count) {
3963
self.fa_matchedRanges = nil;
@@ -43,6 +67,7 @@ - (void) _fa_showPreviewForItem: (id<DVTTextCompletionItem>) item {
4367

4468
NSUInteger previewLength = self.previewRange.length;
4569
NSString *previewText;
70+
NSTextView * textView = (NSTextView *) session.textView;
4671

4772
if (previewLength == item.completionText.length) {
4873
previewText = item.completionText;
@@ -51,23 +76,27 @@ - (void) _fa_showPreviewForItem: (id<DVTTextCompletionItem>) item {
5176
} else if (previewLength == item.displayText.length) {
5277
previewText = item.displayText;
5378
} else {
54-
NSTextView * textView = (NSTextView *) session.textView;
5579
previewText = [[textView.textStorage attributedSubstringFromRange: self.previewRange] string];
5680
}
57-
5881
ranges = [session fa_convertRanges: ranges
5982
fromString: item.name
6083
toString: previewText
6184
addOffset: self.previewRange.location];
6285

6386
if (!ranges.count) {
6487
self.fa_overridedGhostRange = nil;
88+
textView.insertionPointColor = [textView.insertionPointColor colorWithAlphaComponent: 1];
6589
} else {
6690
NSRange lastRange = [[ranges lastObject] rangeValue];
6791
NSUInteger start = NSMaxRange(lastRange);
6892
NSUInteger end = NSMaxRange(self.previewRange);
6993
NSRange override = NSMakeRange(start, end - start);
7094
self.fa_overridedGhostRange = [NSValue valueWithRange: override];
95+
if (![FASettings currentSettings].hideCursorInNonPrefixPreview || session.cursorLocation == start) {
96+
textView.insertionPointColor = [textView.insertionPointColor colorWithAlphaComponent: 1];
97+
} else {
98+
textView.insertionPointColor = [textView.insertionPointColor colorWithAlphaComponent: 0];
99+
}
71100
}
72101

73102
self.fa_matchedRanges = ranges;
@@ -105,3 +134,31 @@ - (void)setFa_overridedGhostRange:(NSValue *)value {
105134
}
106135

107136
@end
137+
138+
@implementation FAPreviewItem {
139+
id<DVTTextCompletionItem> _item;
140+
NSString * _completionText;
141+
}
142+
143+
@dynamic displayType, icon, displayText, descriptionText, priority, notRecommended, parentText, name;
144+
145+
+ (instancetype)previewItemForItem:(id<DVTTextCompletionItem>)item {
146+
FAPreviewItem * ret = [FAPreviewItem new];
147+
ret->_item = item;
148+
NSString * completionText = item.completionText;
149+
completionText = [completionText stringByReplacingOccurrencesOfString:@"<#" withString:@""];
150+
completionText = [completionText stringByReplacingOccurrencesOfString:@"#>" withString:@""];
151+
ret->_completionText = completionText;
152+
return ret;
153+
}
154+
155+
- (id)forwardingTargetForSelector:(SEL)aSelector {
156+
return _item;
157+
}
158+
159+
- (NSString *)completionText {
160+
return _completionText;
161+
}
162+
163+
@end
164+

FuzzyAutocomplete/DVTTextCompletionListWindowController+FuzzyAutocomplete.m

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ + (void) fa_swizzleMethods {
4444
[self jr_swizzleMethod: @selector(_updateCurrentDisplayStateForQuickHelp)
4545
withMethod: @selector(_fa_updateCurrentDisplayStateForQuickHelp)
4646
error: NULL];
47+
48+
[self jr_swizzleMethod: @selector(_preferredWindowFrameForTextFrame:columnsWidth:titleColumnX:)
49+
withMethod: @selector(_fa_preferredWindowFrameForTextFrame:columnsWidth:titleColumnX:)
50+
error: nil];
4751
}
4852

4953
#pragma mark - overrides
@@ -138,6 +142,13 @@ - (void) _fa_updateCurrentDisplayState {
138142
}
139143
}
140144

145+
// We modify titleColumnX with score column's width, so that title column is aligned with typed text
146+
- (CGRect) _fa_preferredWindowFrameForTextFrame: (CGRect) textFrame columnsWidth: (double *) widths titleColumnX: (double) titleX {
147+
NSTableView * tableView = [self valueForKey: @"_completionsTableView"];
148+
return [self _fa_preferredWindowFrameForTextFrame: textFrame columnsWidth: widths titleColumnX: titleX + [self _fa_widthForScoreColumn] + tableView.intercellSpacing.width];
149+
}
150+
151+
141152
// We add visual feedback for the matched ranges. Also format the score column.
142153
- (void) _fa_tableView: (NSTableView *) aTableView
143154
willDisplayCell: (NSCell *) aCell
@@ -152,6 +163,7 @@ - (void) _fa_tableView: (NSTableView *) aTableView
152163
} else if ([aTableColumn.identifier isEqualToString:@"title"]) {
153164
id<DVTTextCompletionItem> item = self.session.filteredCompletionsAlpha[rowIndex];
154165
NSArray * ranges = [self.session fa_matchedRangesForItem: item];
166+
NSArray * second = [self.session fa_secondPassMatchedRangesForItem: item];
155167

156168
if (!ranges.count) {
157169
return;
@@ -164,11 +176,35 @@ - (void) _fa_tableView: (NSTableView *) aTableView
164176
toString: item.displayText
165177
addOffset: 0];
166178

179+
second = [self.session fa_convertRanges: second
180+
fromString: item.name
181+
toString: item.displayText
182+
addOffset: 0];
183+
167184
NSDictionary * attributes = [FATheme cuurrentTheme].listTextAttributesForMatchedRanges;
185+
NSDictionary * altAttributes = [FATheme cuurrentTheme].listTextAttributesForSecondPassMatchedRanges;
168186

169187
for (NSValue * val in ranges) {
170188
[attributed addAttributes: attributes range: [val rangeValue]];
171189
}
190+
for (NSValue * val in second) {
191+
[attributed addAttributes: altAttributes range: [val rangeValue]];
192+
}
193+
194+
195+
NSString * prefix = self.session.usefulPrefix;
196+
if ([item.name hasPrefix: prefix] && ![item.displayText hasPrefix: prefix]) {
197+
NSRange prefixRange = NSMakeRange(0, prefix.length);
198+
NSArray * prefixRanges = [self.session fa_convertRanges: @[ [NSValue valueWithRange: prefixRange] ]
199+
fromString: item.name
200+
toString: item.displayText
201+
addOffset: 0];
202+
prefixRange = NSMakeRange(0, 0);
203+
for (NSValue * val in prefixRanges) {
204+
prefixRange = NSUnionRange(prefixRange, [val rangeValue]);
205+
}
206+
[attributed addAttributes: self._usefulPrefixAttributes range: prefixRange];
207+
}
172208

173209
[aCell setAttributedStringValue: attributed];
174210
}

FuzzyAutocomplete/DVTTextCompletionSession+FuzzyAutocomplete.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
/// Gets array of ranges matched by current search string in given items name.
3131
- (NSArray *) fa_matchedRangesForItem: (id<DVTTextCompletionItem>) item;
3232

33+
/// Gets array of ranges matched in second pass by current search string in given items name.
34+
- (NSArray *) fa_secondPassMatchedRangesForItem: (id<DVTTextCompletionItem>) item;
35+
3336
/// Retrieves a previously calculated autocompletion score for given item.
3437
- (NSNumber *) fa_scoreForItem: (id<DVTTextCompletionItem>) item;
3538

@@ -38,9 +41,11 @@
3841
///
3942
/// Handled cases:
4043
///
41-
/// a) fromString is a substring of toString
44+
/// a) fromString is a substring of toString - offset ranges
45+
///
46+
/// b) both fromString and toString contain word segments
47+
/// try to find ranges within segments (may divide ranges)
4248
///
43-
/// b) both fromString and toString contain segments ending with colons
4449
- (NSArray *) fa_convertRanges: (NSArray *) originalRanges
4550
fromString: (NSString *) fromString
4651
toString: (NSString *) toString

0 commit comments

Comments
 (0)