/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. #import "GTMXcodePluginManager.h"
  19. #import <Cocoa/Cocoa.h>
  20. @interface GTMXcodeCorrectWhitespace : GTMXcodePlugin
  21. - (void)cleanUpWhitespace:(id)sender;
  22. @end
  23. @implementation GTMXcodeCorrectWhitespace
  24. // Perform a "subtraction of ranges". A - B. Not transitive.
  25. static NSRange SubtractRange(NSRange a, NSRange b) {
  26. NSRange newRange;
  27. NSUInteger maxRangeA = NSMaxRange(a);
  28. NSUInteger maxRangeB = NSMaxRange(b);
  29. if (b.location == NSNotFound) {
  30. // B is bogus
  31. newRange = a;
  32. } else if (maxRangeB <= a.location) {
  33. // B is completely before A
  34. newRange = NSMakeRange(a.location - b.length, a.length);
  35. } else if (maxRangeA <= b.location) {
  36. // B is completely after A
  37. newRange = a;
  38. } else if (b.location <= a.location && maxRangeB >= maxRangeA) {
  39. // B subsumes A
  40. newRange = NSMakeRange(b.location, 0);
  41. } else if (a.location <= b.location && maxRangeA >= maxRangeB) {
  42. // A subsumes B
  43. newRange = NSMakeRange(a.location, a.length - b.length);
  44. } else if (b.location <= a.location && maxRangeB <= maxRangeA) {
  45. // B overlaps front edge of A
  46. NSUInteger diff = maxRangeB - a.location;
  47. newRange = NSMakeRange(a.location + diff, a.length - diff);
  48. } else if (b.location <= maxRangeA && maxRangeB >= maxRangeA) {
  49. // B overlaps back edge of A
  50. NSUInteger diff = maxRangeA - b.location;
  51. newRange = NSMakeRange(a.location, a.length - diff);
  52. }
  53. return newRange;
  54. }
  55. + (void)load {
  56. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  57. [GTMXcodePluginManager registerPluginClass:self];
  58. [pool release];
  59. }
  60. - (void)applicationDidFinishLaunching:(NSNotification *)notification {
  61. NSMenu *menu = [NSApp mainMenu];
  62. NSArray *items = [menu itemArray];
  63. for (NSMenuItem *item in items) {
  64. // Added to Edit instead of Editor menu because the Editor menu is
  65. // very dynamic in Xcode4.
  66. if ([[item title] isEqualToString:@"Edit"]) {
  67. NSMenu *editMenu = [item submenu];
  68. [editMenu addItem:[NSMenuItem separatorItem]];
  69. NSMenuItem *whiteSpaceItem
  70. = [[NSMenuItem alloc] initWithTitle:@"Clean Up Whitespace"
  71. action:@selector(cleanUpWhitespace:)
  72. keyEquivalent:@""];
  73. [whiteSpaceItem setKeyEquivalent:@"s"];
  74. [whiteSpaceItem setKeyEquivalentModifierMask:(NSCommandKeyMask |
  75. NSControlKeyMask |
  76. NSAlternateKeyMask)];
  77. [editMenu addItem:whiteSpaceItem];
  78. [whiteSpaceItem setTarget:self];
  79. }
  80. }
  81. }
  82. - (void)cleanUpWhitespace:(id)sender {
  83. NSWindow *nsKeyWindow = [[NSApplication sharedApplication] keyWindow];
  84. NSResponder *responder = [nsKeyWindow firstResponder];
  85. if ([responder conformsToProtocol:@protocol(NSTextInputClient)]) {
  86. id client = responder;
  87. NSRange selectedRange = [client selectedRange];
  88. NSMutableAttributedString *src
  89. = [[[client attributedString] mutableCopy] autorelease];
  90. NSMutableString *text = [NSMutableString stringWithString:[src string]];
  91. // Figure out the newlines in our file.
  92. NSString *newlineString = @"\n";
  93. if ([text rangeOfString:@"\r\n"].length > 0) {
  94. newlineString = @"\r\n";
  95. } else if ([text rangeOfString:@"\r"].length > 0) {
  96. newlineString = @"\r";
  97. }
  98. NSUInteger newlineStringLength = [newlineString length];
  99. NSCharacterSet *whiteSpace
  100. = [NSCharacterSet characterSetWithCharactersInString:@" \t"];
  101. NSMutableCharacterSet *nonWhiteSpace
  102. = [[whiteSpace mutableCopy] autorelease];
  103. [nonWhiteSpace invert];
  104. NSRange oldRange = NSMakeRange(0, [text length]);
  105. NSRange textRange = oldRange;
  106. textRange.length -= 1;
  107. while (textRange.length > 0) {
  108. NSRange lineRange = [text rangeOfString:newlineString
  109. options:NSBackwardsSearch
  110. range:textRange];
  111. if (lineRange.location == NSNotFound) {
  112. lineRange.location = 0;
  113. } else {
  114. lineRange.location += newlineStringLength;
  115. }
  116. lineRange.length = textRange.length - lineRange.location;
  117. textRange.length = lineRange.location;
  118. if (textRange.length != 0) {
  119. textRange.length -= newlineStringLength;
  120. }
  121. NSRange whiteRange = [text rangeOfCharacterFromSet:whiteSpace
  122. options:NSBackwardsSearch
  123. range:lineRange];
  124. if (NSMaxRange(whiteRange) == NSMaxRange(lineRange)) {
  125. NSRange nonWhiteRange = [text rangeOfCharacterFromSet:nonWhiteSpace
  126. options:NSBackwardsSearch
  127. range:lineRange];
  128. NSRange deleteRange;
  129. if (nonWhiteRange.location == NSNotFound) {
  130. deleteRange.location = lineRange.location;
  131. } else {
  132. deleteRange.location = NSMaxRange(nonWhiteRange);
  133. }
  134. deleteRange.length = NSMaxRange(whiteRange) - deleteRange.location;
  135. [text deleteCharactersInRange:deleteRange];
  136. selectedRange = SubtractRange(selectedRange, deleteRange);
  137. }
  138. }
  139. // If the file is missing a newline at the end, add it now.
  140. if (![text hasSuffix:newlineString]) {
  141. [text appendString:newlineString];
  142. }
  143. [client insertText:text replacementRange:oldRange];
  144. if ([client respondsToSelector:@selector(setSelectedRange:)]) {
  145. if (NSMaxRange(selectedRange) < [text length]) {
  146. [client setSelectedRange:selectedRange];
  147. [client scrollRangeToVisible:selectedRange];
  148. }
  149. }
  150. }
  151. }
  152. @end