Skip to content

Commit bf2ce73

Browse files
committed
Fixes #14, #13
- prevents crashes when the current autocompletion session is nil - prevents new line addition on completion request - adds case statement curly brackes - inserting missing cases at the end of the switch statement instead of the beginning - adds default case if missing - other tweaks and fixes
1 parent 776b604 commit bf2ce73

File tree

1 file changed

+67
-36
lines changed

1 file changed

+67
-36
lines changed

SCXcodeSwitchExpander/DVTTextCompletionController+SCXcodeSwitchExpander.m

+67-36
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
@interface DVTTextCompletionListWindowController (SCXcodeSwitchExpander)
2626

27-
- (void)tryExpandingSwitchStatement;
27+
- (BOOL)tryExpandingSwitchStatement;
2828

2929
@end
3030

@@ -42,20 +42,23 @@ + (void)load
4242

4343
- (BOOL)scSwizzledAcceptCurrentCompletion
4444
{
45-
[self.currentSession.listWindowController tryExpandingSwitchStatement];
46-
return [self scSwizzledAcceptCurrentCompletion];
45+
if([self.currentSession.listWindowController tryExpandingSwitchStatement]) {
46+
return YES;
47+
}
48+
49+
return [self scSwizzledAcceptCurrentCompletion];
4750
}
4851

4952
@end
5053

5154
@implementation DVTTextCompletionListWindowController (SCXcodeSwitchExpander)
5255

53-
- (void)tryExpandingSwitchStatement
56+
- (BOOL)tryExpandingSwitchStatement
5457
{
5558
IDEIndex *index = [[SCXcodeSwitchExpander sharedSwitchExpander] index];
5659

5760
if(index == nil) {
58-
return;
61+
return NO;
5962
}
6063

6164
IDEIndexCompletionItem *item = [self _selectedCompletionItem];
@@ -72,70 +75,98 @@ - (void)tryExpandingSwitchStatement
7275

7376
DVTSourceTextView *textView = (DVTSourceTextView *)self.session.textView;
7477
if(self.session.wordStartLocation == NSNotFound) {
75-
return;
78+
return NO;
7679
}
7780

7881
// Fetch the previous new line
7982
NSRange newLineRange = [textView.string rangeOfString:@"\n" options:NSBackwardsSearch range:NSMakeRange(0, self.session.wordStartLocation)];
8083
if(newLineRange.location == NSNotFound) {
81-
return;
84+
return NO;
8285
}
8386

8487
// See if the current line has a switch statement
8588
NSRange switchRange = [textView.string rangeOfString:@"\\s+switch\\s*\\\(" options:NSRegularExpressionSearch range:NSMakeRange(newLineRange.location, self.session.wordStartLocation - newLineRange.location)];
8689
if(switchRange.location == NSNotFound) {
87-
return;
90+
return NO;
8891
}
89-
90-
// Insert the selected autocomplete item
91-
[self.session insertCurrentCompletion];
92-
92+
9393
// Fetch the opening bracket for that switch statement
94-
NSRange openingBracketRange = [textView.string rangeOfString:@"{" options:0 range:NSMakeRange(self.session.wordStartLocation, textView.string.length - self.session.wordStartLocation)];
95-
if(openingBracketRange.location == NSNotFound) {
96-
return;
94+
NSUInteger openingBracketLocation = [textView.string rangeOfString:@"{" options:0 range:NSMakeRange(self.session.wordStartLocation, textView.string.length - self.session.wordStartLocation)].location;
95+
if(openingBracketLocation == NSNotFound) {
96+
return NO;
9797
}
98-
98+
99+
// Insert the selected autocomplete item
100+
[self.session insertCurrentCompletion];
101+
102+
NSRange selectedRange = textView.selectedRange;
103+
99104
// Fetch the closing bracket for that switch statement
100-
NSUInteger closingBracketLocation = [self matchingBracketLocationForOpeningBracketLocation:openingBracketRange.location inString:self.session.textView.string];
105+
NSUInteger closingBracketLocation = [self matchingBracketLocationForOpeningBracketLocation:openingBracketLocation
106+
inString:textView.string];
101107
if(closingBracketLocation == NSNotFound) {
102-
return;
108+
return NO;
103109
}
104-
105-
NSString *switchStatementContents = [self.session.textView.string substringWithRange:NSMakeRange(openingBracketRange.location, closingBracketLocation - openingBracketRange.location)];
106-
110+
107111
// Get rid of the default autocompletion if necessary
108-
NSRange defaultAutocompletionRange = [self.session.textView.string rangeOfString:@"\\s*case <#constant#>:\\s*<#statements#>\\s*break;" options:NSRegularExpressionSearch];
109-
112+
NSRange defaultAutocompletionRange = [textView.string rangeOfString:@"\\s*case <#constant#>:\\s*<#statements#>\\s*break;\\s*default:\\s*break;\\s*" options:NSRegularExpressionSearch range:NSMakeRange(openingBracketLocation, closingBracketLocation - openingBracketLocation)];
110113
if(defaultAutocompletionRange.location != NSNotFound) {
111-
// remove it from the switch
112114
[textView insertText:@"" replacementRange:defaultAutocompletionRange];
115+
closingBracketLocation -= defaultAutocompletionRange.length;
113116
}
114-
115-
// Generate the items to insert
117+
118+
NSRange switchContentRange = NSMakeRange(openingBracketLocation + 1, closingBracketLocation - openingBracketLocation - 1);
119+
NSString *switchContent = [textView.string substringWithRange:switchContentRange];
120+
121+
// Generate the items to insert and insert them at the end
116122
NSMutableString *replacementString = [NSMutableString string];
123+
124+
if([switchContent stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0) {
125+
[replacementString appendString:@"\n"];
126+
}
127+
117128
for(IDEIndexSymbol *child in [((IDEIndexContainerSymbol*)symbol).children allObjects]) {
118-
119-
if([switchStatementContents rangeOfString:child.displayName].location == NSNotFound)
120-
{
121-
[replacementString appendString:[NSString stringWithFormat:@"\ncase %@:\n<#statement#>\nbreak;", child.displayName]];
129+
if([switchContent rangeOfString:child.displayName].location == NSNotFound) {
130+
[replacementString appendString:[NSString stringWithFormat:@"case %@: {\n<#statement#>\nbreak;\n}\n", child.displayName]];
122131
}
123132
}
124-
125-
// Insert the generated items
126-
[textView insertText:replacementString replacementRange:NSMakeRange(openingBracketRange.location + 1, 1)];
127-
133+
134+
[textView insertText:replacementString replacementRange:NSMakeRange(switchContentRange.location + switchContentRange.length, 0)];
135+
136+
closingBracketLocation += replacementString.length;
137+
switchContentRange = NSMakeRange(openingBracketLocation + 1, closingBracketLocation - openingBracketLocation - 1);
138+
switchContent = [textView.string substringWithRange:switchContentRange];
139+
140+
// Insert the default case if necessary
141+
if([switchContent rangeOfString:@"default"].location == NSNotFound) {
142+
replacementString = [NSMutableString stringWithString:@"default: {\nbreak;\n}\n"];
143+
[textView insertText:replacementString replacementRange:NSMakeRange(switchContentRange.location + switchContentRange.length, 0)];
144+
closingBracketLocation += replacementString.length;
145+
}
146+
128147
// Re-indent everything
129-
[textView _indentInsertedTextIfNecessaryAtRange:NSMakeRange(openingBracketRange.location + 1, replacementString.length)];
148+
NSRange reindentRange = NSMakeRange(openingBracketLocation, closingBracketLocation - openingBracketLocation + 2);
149+
[textView _indentInsertedTextIfNecessaryAtRange:reindentRange];
150+
151+
// Preserve the selected range
152+
[textView setSelectedRange:selectedRange];
153+
154+
return YES;
130155
}
131156

132157
break;
133158
}
159+
160+
return NO;
134161
}
135162

136163
- (NSUInteger)matchingBracketLocationForOpeningBracketLocation:(NSUInteger)location inString:(NSString *)string
137164
{
138-
const char *cString = [self.session.textView.string cStringUsingEncoding:NSUTF8StringEncoding];
165+
if(string.length == 0) {
166+
return NSNotFound;
167+
}
168+
169+
const char *cString = [string cStringUsingEncoding:NSUTF8StringEncoding];
139170

140171
NSInteger matchingLocation = location;
141172
NSInteger counter = 1;

0 commit comments

Comments
 (0)