Commits

Jens Alfke committed b68df17

More FileViewer work: Enable blame links, suppress duplicate windows.

Comments (0)

Files changed (12)

English.lproj/FileViewer.strings

+
+/* Class = "NSButton"; gToolTip = "Previous revision"; ObjectID = "22"; */
+"22.gToolTip" = "Previous revision";
+
+/* Class = "NSButton"; gToolTip = "Next revision"; ObjectID = "24"; */
+"24.gToolTip" = "Next revision";
+
+/* Class = "NSSegmentedCell"; 29.labels[0] = "Source"; ObjectID = "29"; */
+"29.labels[0]" = "Source";
+
+/* Class = "NSSegmentedCell"; 29.labels[1] = "Diff"; ObjectID = "29"; */
+"29.labels[1]" = "Diff";
+
+/* Class = "NSSegmentedCell"; 29.labels[2] = "Blame"; ObjectID = "29"; */
+"29.labels[2]" = "Blame";

English.lproj/FileViewer.xib

 		</object>
 		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
 			<bool key="EncodedWithXMLCoder">YES</bool>
-			<integer value="3"/>
+			<integer value="1"/>
 		</object>
 		<object class="NSArray" key="IBDocument.PluginDependencies">
 			<bool key="EncodedWithXMLCoder">YES</bool>
 			<object class="NSWindowTemplate" id="1005">
 				<int key="NSWindowStyleMask">15</int>
 				<int key="NSWindowBacking">2</int>
-				<string key="NSWindowRect">{{188, 186}, {578, 692}}</string>
-				<int key="NSWTFlags">544735232</int>
-				<string key="NSWindowTitle">/Path/To/File</string>
+				<string key="NSWindowRect">{{161, 28}, {662, 828}}</string>
+				<int key="NSWTFlags">543687680</int>
+				<string key="NSWindowTitle"/>
 				<string key="NSWindowClass">NSWindow</string>
 				<nil key="NSViewClass"/>
 				<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
 													<string>public.url</string>
 												</object>
 											</object>
-											<string key="NSFrameSize">{578, 29}</string>
+											<string key="NSFrameSize">{662, 29}</string>
 											<reference key="NSSuperview" ref="64418832"/>
 											<object class="NSTextContainer" key="NSTextContainer" id="249538336">
 												<object class="NSLayoutManager" key="NSLayoutManager">
 													<nil key="NSDelegate"/>
 												</object>
 												<reference key="NSTextView" ref="64985884"/>
-												<double key="NSWidth">578</double>
+												<double key="NSWidth">662</double>
 												<int key="NSTCFlags">1</int>
 											</object>
 											<object class="NSTextViewSharedData" key="NSSharedData">
 												<nil key="NSDefaultParagraphStyle"/>
 											</object>
 											<int key="NSTVFlags">6</int>
-											<string key="NSMaxSize">{1158, 1e+07}</string>
+											<string key="NSMaxSize">{1326, 1e+07}</string>
 											<string key="NSMinize">{223, 0}</string>
 											<nil key="NSDelegate"/>
 										</object>
 									</object>
-									<string key="NSFrame">{{1, 1}, {578, 638}}</string>
+									<string key="NSFrame">{{1, 1}, {662, 774}}</string>
 									<reference key="NSSuperview" ref="83548836"/>
 									<reference key="NSNextKeyView" ref="64985884"/>
 									<reference key="NSDocView" ref="64985884"/>
 									<double key="NSPercent">0.94565218687057495</double>
 								</object>
 							</object>
-							<string key="NSFrame">{{-1, 21}, {580, 640}}</string>
+							<string key="NSFrame">{{-1, 21}, {664, 776}}</string>
 							<reference key="NSSuperview" ref="1006"/>
 							<reference key="NSNextKeyView" ref="64418832"/>
 							<int key="NSsFlags">562</int>
 						<object class="NSSlider" id="771270540">
 							<reference key="NSNextResponder" ref="1006"/>
 							<int key="NSvFlags">266</int>
-							<string key="NSFrame">{{21, 662}, {535, 26}}</string>
+							<string key="NSFrame">{{21, 798}, {619, 26}}</string>
 							<reference key="NSSuperview" ref="1006"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSSliderCell" key="NSCell" id="1045305343">
-								<int key="NSCellFlags">-2079981824</int>
+								<int key="NSCellFlags">-2080244224</int>
 								<int key="NSCellFlags2">0</int>
 								<string key="NSContents"/>
 								<reference key="NSControlView" ref="771270540"/>
 						<object class="NSButton" id="660499110">
 							<reference key="NSNextResponder" ref="1006"/>
 							<int key="NSvFlags">268</int>
-							<string key="NSFrame">{{0, 664}, {16, 16}}</string>
+							<string key="NSFrame">{{0, 800}, {16, 16}}</string>
 							<reference key="NSSuperview" ref="1006"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSButtonCell" key="NSCell" id="117490355">
 						<object class="NSButton" id="308381493">
 							<reference key="NSNextResponder" ref="1006"/>
 							<int key="NSvFlags">265</int>
-							<string key="NSFrame">{{560, 664}, {16, 16}}</string>
+							<string key="NSFrame">{{644, 800}, {16, 16}}</string>
 							<reference key="NSSuperview" ref="1006"/>
 							<bool key="NSEnabled">YES</bool>
 							<object class="NSButtonCell" key="NSCell" id="1026166696">
 							</object>
 						</object>
 					</object>
-					<string key="NSFrameSize">{578, 692}</string>
+					<string key="NSFrameSize">{662, 828}</string>
 					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
 				<string key="NSMinSize">{250, 222}</string>
 				<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
-				<bool key="NSAutorecalculatesContentBorderThicknessMinY">NO</bool>
 				<double key="NSContentBorderThicknessMinY">22</double>
 			</object>
 		</object>
 					</object>
 					<int key="connectionID">31</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">delegate</string>
+						<reference key="source" ref="1005"/>
+						<reference key="destination" ref="1001"/>
+					</object>
+					<int key="connectionID">32</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">initialFirstResponder</string>
+						<reference key="source" ref="1005"/>
+						<reference key="destination" ref="83548836"/>
+					</object>
+					<int key="connectionID">33</int>
+				</object>
 			</object>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<object class="NSArray" key="orderedObjects">
 					<string>14.CustomClassName</string>
 					<string>14.IBPluginDependency</string>
 					<string>2.IBPluginDependency</string>
+					<string>22.IBAttributePlaceholdersKey</string>
 					<string>22.IBPluginDependency</string>
 					<string>23.IBPluginDependency</string>
+					<string>24.IBAttributePlaceholdersKey</string>
 					<string>24.IBPluginDependency</string>
 					<string>25.IBPluginDependency</string>
 					<string>28.IBPluginDependency</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{200, 138}, {578, 692}}</string>
+					<string>{{161, 28}, {662, 828}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{200, 138}, {578, 692}}</string>
+					<string>{{161, 28}, {662, 828}}</string>
 					<boolean value="NO"/>
 					<string>{196, 240}</string>
 					<string>{{357, 418}, {480, 270}}</string>
 					<string>RevisionSliderCell</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<object class="NSMutableDictionary">
+						<string key="NS.key.0">ToolTip</string>
+						<object class="IBToolTipAttribute" key="NS.object.0">
+							<string key="name">ToolTip</string>
+							<reference key="object" ref="660499110"/>
+							<string key="toolTip">Previous revision</string>
+						</object>
+					</object>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<object class="NSMutableDictionary">
+						<string key="NS.key.0">ToolTip</string>
+						<object class="IBToolTipAttribute" key="NS.object.0">
+							<string key="name">ToolTip</string>
+							<reference key="object" ref="308381493"/>
+							<string key="toolTip">Next revision</string>
+						</object>
+					</object>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 				</object>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">31</int>
+			<int key="maxID">33</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
 						<bool key="EncodedWithXMLCoder">YES</bool>
 						<object class="NSArray" key="dict.sortedKeys">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<string>_infoField</string>
 							<string>_revisionSlider</string>
 							<string>_textView</string>
 						</object>
 						<object class="NSMutableArray" key="dict.values">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<string>NSTextField</string>
 							<string>NSSlider</string>
 							<string>NSTextView</string>
 						</object>
 					</object>
 				</object>
 				<object class="IBPartialClassDescription">
-					<string key="className">NSTextField</string>
-					<string key="superclassName">NSControl</string>
-					<object class="IBClassDescriptionSource" key="sourceIdentifier">
-						<string key="majorKey">IBFrameworkSource</string>
-						<string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
-					</object>
-				</object>
-				<object class="IBPartialClassDescription">
 					<string key="className">NSTextView</string>
 					<string key="superclassName">NSText</string>
 					<object class="IBClassDescriptionSource" key="sourceIdentifier">

French.lproj/FileViewer.strings

+
+/* Class = "NSWindow"; title = "/Path/To/File"; ObjectID = "1"; */
+"1.title" = "/Path/To/File";
+
+/* Class = "NSSegmentedCell"; 29.labels[0] = "Source"; ObjectID = "29"; */
+"29.labels[0]" = "Source";
+
+/* Class = "NSSegmentedCell"; 29.labels[1] = "Diff"; ObjectID = "29"; */
+"29.labels[1]" = "Diff";
+
+/* Class = "NSSegmentedCell"; 29.labels[2] = "Blame"; ObjectID = "29"; */
+"29.labels[2]" = "Blame";

German.lproj/FileViewer.strings

+
+/* Class = "NSWindow"; title = "/Path/To/File"; ObjectID = "1"; */
+"1.title" = "/Path/To/File";
+
+/* Class = "NSSegmentedCell"; 29.labels[0] = "Source"; ObjectID = "29"; */
+"29.labels[0]" = "Source";
+
+/* Class = "NSSegmentedCell"; 29.labels[1] = "Diff"; ObjectID = "29"; */
+"29.labels[1]" = "Diff";
+
+/* Class = "NSSegmentedCell"; 29.labels[2] = "Blame"; ObjectID = "29"; */
+"29.labels[2]" = "Blame";
 {
+    "French.lproj/Projects.strings": "7f3632a7668f39432d8dbf4ffb770f55", 
     "French.lproj/Repo.strings": "1c882f55c1bc1e7629827090aae1f4ed", 
-    "French.lproj/Projects.strings": "7f3632a7668f39432d8dbf4ffb770f55", 
+    "English.lproj/Projects.xib": "770fab372e314ce3a66f4c501d11d8ee", 
     "German.lproj/FileViewer.strings": "3180f066f393da424f8f32f60384cedf", 
-    "English.lproj/Projects.xib": "770fab372e314ce3a66f4c501d11d8ee", 
-    "English.lproj/FileViewer.xib": "17b4ba07d4355b7e4f08473339aa7fcd", 
+    "English.lproj/FileViewer.xib": "40459694d28926007c88425e8b9a1a7e", 
     "English.lproj/MainMenu.xib": "4e93964b3a4de3e2acf8477112c04720", 
     "German.lproj/Projects.strings": "8554bdd35568c0d598d3f5b322836067", 
     "German.lproj/Repo.strings": "8bb4aeacd068f7b82e02806076095383", 

Murky.xcodeproj/project.pbxproj

 				270E51280C56AD520069C9C6 /* HgLogOperation.m */,
 				2712F0520C581F5300E36E41 /* HgTempDir.h */,
 				2712F0530C581F5300E36E41 /* HgTempDir.m */,
+				7341D0BD10F470E000076123 /* IconTextCell.h */,
+				7341D0BE10F470E000076123 /* IconTextCell.m */,
 				27107D1C0C887D3700ED7715 /* Predicate.h */,
 				27107D1D0C887D3700ED7715 /* Predicate.m */,
 				272AB4C80C8DD2600068C695 /* HgConfigFile.h */,
 				272AB4C90C8DD2600068C695 /* HgConfigFile.m */,
+				27C1C934104EF9F400781C99 /* SourceHighlighting.h */,
+				27C1C935104EF9F400781C99 /* SourceHighlighting.m */,
+				73CA824710135EC90081F0D8 /* Terminal.h */,
 				27D124F40C8F501B0075446A /* URLFormatter.h */,
 				27D124F50C8F501B0075446A /* URLFormatter.m */,
-				73CA824710135EC90081F0D8 /* Terminal.h */,
-				27C1C934104EF9F400781C99 /* SourceHighlighting.h */,
-				27C1C935104EF9F400781C99 /* SourceHighlighting.m */,
 				32CA4F630368D1EE00C91783 /* Murky_Prefix.pch */,
-				7341D0BD10F470E000076123 /* IconTextCell.h */,
-				7341D0BE10F470E000076123 /* IconTextCell.m */,
 			);
 			name = Support;
 			path = Source;

Source/FileViewer.h

     
     IBOutlet NSTextView* _textView;
     IBOutlet NSSlider* _revisionSlider;
-    IBOutlet NSTextField* _infoField;
 }
 
-- (id) initWithFile: (HgFile*)file;
++ (FileViewer*) fileViewerWithFile: (HgFile*)file;
 
 @property (readonly) HgFile* file;
 @property HgRevision* revision;

Source/FileViewer.m

     return self;
 }
 
++ (NSArray*) allFileViewers
+{
+    NSMutableArray *openRepos = [NSMutableArray array];
+    for( NSWindow *window in [NSApp windows]) {
+        id delegate = [window delegate];
+        if( [window isVisible] && [delegate isKindOfClass: self] ) {
+            [openRepos addObject: delegate];
+        }
+    }
+    return openRepos;
+}
+
++ (FileViewer*) existingFileViewerWithFile: (HgFile*)file
+{
+    NSString* path = file.path;
+    HgRepository* repository = file.repository;
+    for( FileViewer *fileViewer in [self allFileViewers]) {
+        if (fileViewer.revision.repository == repository
+               && [fileViewer.file.path isEqualToString: path])
+            return fileViewer;
+    }
+    return nil;
+}
+
++ (FileViewer*) fileViewerWithFile: (HgFile*)file
+{
+    FileViewer *controller = [self existingFileViewerWithFile: file];
+    if (controller)
+        controller.file = file;     // set revision to match
+    else
+        controller = [[self alloc] initWithFile: file];
+    return controller;
+}
+
+
 - (void) awakeFromNib {
     HgFile *file = _file;
-    self.window.title = $sprintf(@"%@ in %@ at %@", 
-                                 _file.name, _file.repository.name, _file.directory.path);
+    [self.window setContentBorderThickness: 22 forEdge: NSMinYEdge];
     [self setTextWraps: NO];
     
     HgRepository *repository = file.repository;
         self.file = file;
 }
 
-- (HgFile*) file {
-    return _file;
-}
-
-- (void) setFile: (HgFile*)file {
-    Assert(file!=nil);
-    _file = file;
-    HgRevision *revision = _file.revision;
-    if (revision.isUncommitted) {
-        _revisionSlider.intValue = (int)_revisionSlider.maxValue;
-        _infoField.stringValue = @"Current contents (uncommitted)";
-    } else {
-        _revisionSlider.intValue = revision.localNumber;
-        _infoField.stringValue = $sprintf(@"r%i — %@", 
-                                          revision.localNumber, revision.date);
-    }
-    [self _showFileContents];
-}
-
-
-- (HgRevision*) revision {
-    return _file.revision;
-}
-
-- (void) setRevision: (HgRevision*)revision {
-    HgFile *file = [revision fileAtPath: _file.path];
-    if (file && file != _file)
-        self.file = file;
-}
-
-- (BOOL) skipRevision: (int)delta {
-    NSArray *revisions = [_revisionSlider.cell revisions];
-    int index = [revisions indexOfObject: self.revision];
-    if (index==NSNotFound)
-        return NO;
-    index += delta;
-    if (index<0 || index>=(int)revisions.count)
-        return NO;
-    self.revision = [revisions objectAtIndex: index];
-    return YES;
-}
-
-
-- (FileViewMode) viewMode {return _viewMode;}
-
-- (void) setViewMode:(FileViewMode)mode {
-    if (mode != _viewMode) {
-        _viewMode = mode;
-        [self _showFileContents];
-    }
-}
-
-
-- (IBAction) sliderChanged: (id)sender {
-    int revNo = _revisionSlider.intValue;
-    self.revision = [[_file.repository revisions] objectAtIndex: revNo];
-}
-
-- (IBAction) prevRevision: (id)sender {
-    if (![self skipRevision: -1])
-        NSBeep();
-}
-
-- (IBAction) nextRevision: (id)sender {
-    if (![self skipRevision: 1])
-        NSBeep();
-}
-
-
-- (BOOL) textWraps {
-    return [_textView isHorizontallyResizable];
-}
-
-- (void) setTextWraps: (BOOL)wraps {
-    [_textView setHorizontallyResizable: !wraps];
-    NSSize containerSize = _textView.textContainer.containerSize;
-    containerSize.width = wraps ?_textView.enclosingScrollView.documentVisibleRect.size.width 
-                                :FLT_MAX;
-    [[_textView textContainer] setContainerSize: containerSize];
-    [[_textView textContainer] setWidthTracksTextView: wraps];
-    [[_textView enclosingScrollView] setHasHorizontalScroller: !wraps];
-    [_textView setNeedsDisplay: YES];
-}
-
 
 - (NSArray*) revTooltips {
     NSArray *revisions = _file.repository.revisions;
     NSError *error = nil;
     NSMutableAttributedString *text = nil;
     
-    switch (_viewMode) {
+    FileViewMode mode = _viewMode;
+    if (mode==kViewBlame && revision.isUncommitted)
+        mode = kViewSource;     // "hg blame" won't show current edits, so disallow it
+    
+    switch (mode) {
         case kViewSource: {
             NSData *contents = [revision getFileContents: _file error: &error];
             if (contents) {
     [_textView setNeedsDisplay: YES];
 }
 
+
+#pragma mark -
+#pragma mark ACCESSORS:
+
+
+- (HgFile*) file {
+    return _file;
+}
+
+- (void) setFile: (HgFile*)file {
+    Assert(file!=nil);
+    _file = file;
+    HgRevision *revision = _file.revision;
+    NSString *name = _file.name;
+    if (revision.isUncommitted) {
+        _revisionSlider.intValue = (int)_revisionSlider.maxValue;
+    } else {
+        _revisionSlider.intValue = revision.localNumber;
+        name = [name stringByAppendingFormat: @" r%i", revision.localNumber];
+    }
+    self.window.title = $sprintf(NSLocalizedString(@"%@ in %@",
+                                   @"FileViewer window title pattern (filename,repository)"),
+                                 name, _file.repository.name, _file.directory.path);
+    [self _showFileContents];
+}
+
+
+- (HgRevision*) revision {
+    return _file.revision;
+}
+
+- (void) setRevision: (HgRevision*)revision {
+    HgFile *file = [revision fileAtPath: _file.path];
+    if (file && file != _file)
+        self.file = file;
+}
+
+- (BOOL) skipRevision: (int)delta {
+    NSArray *revisions = [_revisionSlider.cell revisions];
+    int index = [revisions indexOfObject: self.revision];
+    if (index==NSNotFound)
+        return NO;
+    index += delta;
+    if (index<0 || index>=(int)revisions.count)
+        return NO;
+    self.revision = [revisions objectAtIndex: index];
+    return YES;
+}
+
+
+- (FileViewMode) viewMode {return _viewMode;}
+
+- (void) setViewMode:(FileViewMode)mode {
+    if (mode != _viewMode) {
+        _viewMode = mode;
+        [self _showFileContents];
+    }
+}
+
+
+#pragma mark -
+#pragma mark ACTIONS:
+
+
+- (IBAction) sliderChanged: (id)sender {
+    int revNo = _revisionSlider.intValue;
+    self.revision = [[_file.repository revisions] objectAtIndex: revNo];
+}
+
+- (IBAction) prevRevision: (id)sender {
+    if (![self skipRevision: -1])
+        NSBeep();
+}
+
+- (IBAction) nextRevision: (id)sender {
+    if (![self skipRevision: 1])
+        NSBeep();
+}
+
+
+- (BOOL) textWraps {
+    return [_textView isHorizontallyResizable];
+}
+
+- (void) setTextWraps: (BOOL)wraps {
+    [_textView setHorizontallyResizable: !wraps];
+    NSSize containerSize = _textView.textContainer.containerSize;
+    containerSize.width = wraps ?_textView.enclosingScrollView.documentVisibleRect.size.width 
+                                :FLT_MAX;
+    [[_textView textContainer] setContainerSize: containerSize];
+    [[_textView textContainer] setWidthTracksTextView: wraps];
+    [[_textView enclosingScrollView] setHasHorizontalScroller: !wraps];
+    [_textView setNeedsDisplay: YES];
+}
+
+
 - (BOOL)textView:(NSTextView *)textView clickedOnLink:(id)link atIndex:(NSUInteger)charIndex {
-    NSLog(@"clicked on: %@", link);
-    return YES;
+    if ([link isKindOfClass: [NSNumber class]]) {
+        // HighlightAnnotatedFile creates links to revision numbers: 
+        _revisionSlider.intValue = [link intValue];
+        [self sliderChanged:_revisionSlider];
+        return YES;
+    }
+    return NO;
 }
 
 @end
 
 
 
-
+#pragma mark -
 @implementation RevisionSliderCell
 
 static NSDictionary *sTickAttrs;
                        cellFrame.origin.y + r.origin.y + 4};
         NSString *label = rev.localString;
         float width = [label sizeWithAttributes: sTickAttrs].width;
-        org.x = org.x + 2.0f - floorf(width/2.0f);
+        org.x = org.x + 2.0f - floorf(width/2.0f);      // center
+        org.x = MIN(org.x, NSMaxX([controlView bounds]) - width);  // pin to right edge
         if (org.x >= xClear) {  // don't let labels overlap
             [label drawAtPoint: org withAttributes: sTickAttrs];
             xClear = org.x + width;
 
 - (void)drawKnob:(NSRect)knobRect {
     [super drawKnob: knobRect];
+    
+    // Don't show the uncommitted revision
+    int revNo = self.intValue;
+    if (revNo == self.maxValue) {
+        HgRevision *lastRev = _revisions.lastObject;
+        if (lastRev.isUncommitted)
+            return;
+    }
+    
+    // Else show the revision number in the knob:
     NSString *label = $sprintf(@"%i", self.intValue);
     NSSize size = [label sizeWithAttributes: sTickAttrs];
     NSPoint org = {roundf(NSMidX(knobRect) - size.width/2.0f),

Source/RepoController.h

 
 + (NSArray*) allRepoControllers;
 + (RepoController*) existingRepoControllerWithDirectory: (NSString*)directory;
++ (RepoController*) existingRepoControllerWithRepository: (HgRepository*)repo;
 + (RepoController*) repoControllerWithDirectory: (NSString*)directory 
                                           error: (NSError**)error;
 - (id) initWithDirectory: (NSString*)path 

Source/RepoController.m

 }
 
 
++ (RepoController*) existingRepoControllerWithRepository: (HgRepository*)repo
+{
+    for( RepoController *repoController in [self allRepoControllers]) {
+        if( [repoController repository] == repo )
+            return repoController;
+    }
+    return nil;
+}
+
+
 + (RepoController*) existingRepoControllerWithDirectory: (NSString*)directory
 {
     directory = [HgRepository findRootOf: directory localPath: nil];

Source/RepoController_Actions.m

         NSBeep();
         return;
     }
-    FileViewer *viewer = [[FileViewer alloc] initWithFile: file];
+    FileViewer *viewer = [FileViewer fileViewerWithFile: file];
     [viewer showWindow: sender];
 }
 

Source/SourceHighlighting.m

         }
         if (attrs) {
             [text addAttributes: attrs range: NSMakeRange(lineStart,nextStart-lineStart)];
-            NSString *tooltip = [revToolTips objectAtIndex: revNo];
-            [text addAttributes: $dict({NSToolTipAttributeName, tooltip},
-                                       {NSLinkAttributeName, $object(revNo)})
-                          range: NSMakeRange(lineStart,lineStart+4)];
+            if (revNo != curRevNo) {
+                NSString *tooltip = [revToolTips objectAtIndex: revNo];
+                [text addAttributes: $dict({NSToolTipAttributeName, tooltip},
+                                           {NSLinkAttributeName, $object(revNo)})
+                              range: NSMakeRange(lineStart,4)];
+            }
         }
     }
 }