PageRenderTime 73ms CodeModel.GetById 14ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/Xcode4Plugin/GTMXcodeCorrectWhitespace.m

http://macfuse.googlecode.com/
Objective C | 165 lines | 123 code | 13 blank | 29 comment | 38 complexity | 0f5d1eb650cd8dc4c1bf31e1c7d9b1b5 MD5 | raw file
  1//
  2//  GTMXcodeCorrectWhitespace.m
  3//
  4//  Copyright 2007-2011 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMXcodePluginManager.h"
 20#import <Cocoa/Cocoa.h>
 21
 22@interface GTMXcodeCorrectWhitespace : GTMXcodePlugin
 23- (void)cleanUpWhitespace:(id)sender;
 24@end
 25
 26@implementation GTMXcodeCorrectWhitespace
 27
 28// Perform a "subtraction of ranges". A - B. Not transitive.
 29static NSRange SubtractRange(NSRange a, NSRange b) {
 30  NSRange newRange;
 31  NSUInteger maxRangeA = NSMaxRange(a);
 32  NSUInteger maxRangeB = NSMaxRange(b);
 33  if (b.location == NSNotFound) {
 34    // B is bogus
 35    newRange = a;
 36  } else if (maxRangeB <= a.location) {
 37    // B is completely before A
 38    newRange = NSMakeRange(a.location - b.length, a.length);
 39  } else if (maxRangeA <= b.location) {
 40    // B is completely after A
 41    newRange = a;
 42  } else if (b.location <= a.location && maxRangeB >= maxRangeA) {
 43    // B subsumes A
 44    newRange = NSMakeRange(b.location, 0);
 45  } else if (a.location <= b.location && maxRangeA >= maxRangeB) {
 46    // A subsumes B
 47    newRange = NSMakeRange(a.location, a.length - b.length);
 48  } else if (b.location <= a.location && maxRangeB <= maxRangeA) {
 49    // B overlaps front edge of A
 50    NSUInteger diff = maxRangeB - a.location;
 51    newRange = NSMakeRange(a.location + diff, a.length - diff);
 52  } else if (b.location <= maxRangeA && maxRangeB >= maxRangeA) {
 53    // B overlaps back edge of A
 54    NSUInteger diff = maxRangeA - b.location;
 55    newRange = NSMakeRange(a.location, a.length - diff);
 56  }
 57  return newRange;
 58}
 59
 60+ (void)load {
 61  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 62  [GTMXcodePluginManager registerPluginClass:self];
 63  [pool release];
 64}
 65
 66- (void)applicationDidFinishLaunching:(NSNotification *)notification {
 67  NSMenu *menu = [NSApp mainMenu];
 68  NSArray *items = [menu itemArray];
 69  for (NSMenuItem *item in items) {
 70    // Added to Edit instead of Editor menu because the Editor menu is
 71    // very dynamic in Xcode4.
 72    if ([[item title] isEqualToString:@"Edit"]) {
 73      NSMenu *editMenu = [item submenu];
 74      [editMenu addItem:[NSMenuItem separatorItem]];
 75      NSMenuItem *whiteSpaceItem
 76          = [[NSMenuItem alloc] initWithTitle:@"Clean Up Whitespace"
 77                                       action:@selector(cleanUpWhitespace:)
 78                                keyEquivalent:@""];
 79      [whiteSpaceItem setKeyEquivalent:@"s"];
 80      [whiteSpaceItem setKeyEquivalentModifierMask:(NSCommandKeyMask |
 81                                                    NSControlKeyMask |
 82                                                    NSAlternateKeyMask)];
 83      [editMenu addItem:whiteSpaceItem];
 84      [whiteSpaceItem setTarget:self];
 85    }
 86  }
 87}
 88
 89- (void)cleanUpWhitespace:(id)sender {
 90  NSWindow *nsKeyWindow = [[NSApplication sharedApplication] keyWindow];
 91  NSResponder *responder = [nsKeyWindow firstResponder];
 92  if ([responder conformsToProtocol:@protocol(NSTextInputClient)]) {
 93    id client = responder;
 94    NSRange selectedRange = [client selectedRange];
 95    NSMutableAttributedString *src
 96        = [[[client attributedString] mutableCopy] autorelease];
 97    NSMutableString *text = [NSMutableString stringWithString:[src string]];
 98
 99    // Figure out the newlines in our file.
100    NSString *newlineString = @"\n";
101    if ([text rangeOfString:@"\r\n"].length > 0) {
102      newlineString = @"\r\n";
103    } else if ([text rangeOfString:@"\r"].length > 0) {
104      newlineString = @"\r";
105    }
106    NSUInteger newlineStringLength = [newlineString length];
107    NSCharacterSet *whiteSpace
108        = [NSCharacterSet characterSetWithCharactersInString:@" \t"];
109    NSMutableCharacterSet *nonWhiteSpace
110        = [[whiteSpace mutableCopy] autorelease];
111    [nonWhiteSpace invert];
112
113    NSRange oldRange = NSMakeRange(0, [text length]);
114    NSRange textRange = oldRange;
115    textRange.length -= 1;
116    while (textRange.length > 0) {
117      NSRange lineRange = [text rangeOfString:newlineString
118                                      options:NSBackwardsSearch
119                                        range:textRange];
120      if (lineRange.location == NSNotFound) {
121        lineRange.location = 0;
122      } else {
123        lineRange.location += newlineStringLength;
124      }
125      lineRange.length = textRange.length - lineRange.location;
126      textRange.length = lineRange.location;
127      if (textRange.length != 0) {
128        textRange.length -= newlineStringLength;
129      }
130
131      NSRange whiteRange = [text rangeOfCharacterFromSet:whiteSpace
132                                                 options:NSBackwardsSearch
133                                                   range:lineRange];
134      if (NSMaxRange(whiteRange) == NSMaxRange(lineRange)) {
135        NSRange nonWhiteRange = [text rangeOfCharacterFromSet:nonWhiteSpace
136                                                      options:NSBackwardsSearch
137                                                        range:lineRange];
138        NSRange deleteRange;
139        if (nonWhiteRange.location == NSNotFound) {
140          deleteRange.location = lineRange.location;
141        } else {
142          deleteRange.location = NSMaxRange(nonWhiteRange);
143        }
144        deleteRange.length = NSMaxRange(whiteRange) - deleteRange.location;
145        [text deleteCharactersInRange:deleteRange];
146        selectedRange = SubtractRange(selectedRange, deleteRange);
147      }
148    }
149
150    // If the file is missing a newline at the end, add it now.
151    if (![text hasSuffix:newlineString]) {
152      [text appendString:newlineString];
153    }
154
155    [client insertText:text replacementRange:oldRange];
156    if ([client respondsToSelector:@selector(setSelectedRange:)]) {
157      if (NSMaxRange(selectedRange) < [text length]) {
158        [client setSelectedRange:selectedRange];
159        [client scrollRangeToVisible:selectedRange];
160      }
161    }
162  }
163}
164
165@end