Skip to content
Snippets Groups Projects
Commit 9d8e31cd authored by George Nachman's avatar George Nachman
Browse files

Fix various bugs with highlighting of search results.

- Resizing a session would clear the find state, removing search results until the next search
- Clearing a buffer would remove highlights but not search results so they wouldn't reappear

Issue 5865.
parent b4bb1c2a
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -1127,7 +1127,7 @@ DQ
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" id="Moz-RU-iUF">
<rect key="frame" x="1" y="0.0" width="533" height="153"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" headerView="6284" id="6283">
<rect key="frame" x="0.0" y="0.0" width="533" height="136"/>
Loading
Loading
@@ -3695,8 +3695,8 @@ DQ
<outlet property="delegate" destination="TG6-06-mq9" id="0fm-Vp-V0B"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="RGW-48-LkR">
<rect key="frame" x="379" y="38" width="55" height="18"/>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" id="RGW-48-LkR">
<rect key="frame" x="381" y="39" width="73" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="seconds" id="VbV-8M-87X">
<font key="font" metaFont="system"/>
Loading
Loading
Loading
Loading
@@ -1696,6 +1696,8 @@
A68A3119186E2F54007F550F /* PopupModel.h in Headers */ = {isa = PBXBuildFile; fileRef = A68A3117186E2F54007F550F /* PopupModel.h */; };
A68AC8F31F05C0860023A216 /* NSBundle+iTerm.h in Headers */ = {isa = PBXBuildFile; fileRef = A68AC8F11F05C0860023A216 /* NSBundle+iTerm.h */; };
A68AC8F41F05C0860023A216 /* NSBundle+iTerm.m in Sources */ = {isa = PBXBuildFile; fileRef = A68AC8F21F05C0860023A216 /* NSBundle+iTerm.m */; };
A68AC8F61F0823100023A216 /* iTermFindOnPageHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A68AC8F51F0823100023A216 /* iTermFindOnPageHelperTest.m */; };
A68AC8F71F0823100023A216 /* iTermFindOnPageHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A68AC8F51F0823100023A216 /* iTermFindOnPageHelperTest.m */; };
A68BADFB1E0DD52F00E4BB7B /* Touch Bar Function Keys.png in Resources */ = {isa = PBXBuildFile; fileRef = A68BADF91E0DD52F00E4BB7B /* Touch Bar Function Keys.png */; };
A68BADFC1E0DD52F00E4BB7B /* Touch Bar Function Keys@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A68BADFA1E0DD52F00E4BB7B /* Touch Bar Function Keys@2x.png */; };
A68E332B1DE6AFC6003F1D8E /* iTermTouchBarButton.h in Headers */ = {isa = PBXBuildFile; fileRef = A68E33291DE6AFC6003F1D8E /* iTermTouchBarButton.h */; };
Loading
Loading
@@ -3611,6 +3613,7 @@
A68A3118186E2F54007F550F /* PopupModel.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = PopupModel.m; sourceTree = "<group>"; tabWidth = 4; };
A68AC8F11F05C0860023A216 /* NSBundle+iTerm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+iTerm.h"; sourceTree = "<group>"; };
A68AC8F21F05C0860023A216 /* NSBundle+iTerm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+iTerm.m"; sourceTree = "<group>"; };
A68AC8F51F0823100023A216 /* iTermFindOnPageHelperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermFindOnPageHelperTest.m; sourceTree = "<group>"; };
A68BADF91E0DD52F00E4BB7B /* Touch Bar Function Keys.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Touch Bar Function Keys.png"; path = "images/Touch Bar Function Keys.png"; sourceTree = "<group>"; };
A68BADFA1E0DD52F00E4BB7B /* Touch Bar Function Keys@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Touch Bar Function Keys@2x.png"; path = "images/Touch Bar Function Keys@2x.png"; sourceTree = "<group>"; };
A68E33291DE6AFC6003F1D8E /* iTermTouchBarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermTouchBarButton.h; sourceTree = "<group>"; };
Loading
Loading
@@ -5811,6 +5814,7 @@
A6C7641D1B45CB2800E3C992 /* iTerm2XCTests */ = {
isa = PBXGroup;
children = (
A68AC8F51F0823100023A216 /* iTermFindOnPageHelperTest.m */,
A60BB3901EB6A56800D76C09 /* iTermProcessCollectionTest.m */,
C6675EB91C4FE95E0041173B /* Utilities */,
A6D22B431BC9D368004084E0 /* iTermShellHistoryTest.m */,
Loading
Loading
@@ -8353,6 +8357,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A68AC8F61F0823100023A216 /* iTermFindOnPageHelperTest.m in Sources */,
90A1E13B186F9EA4003EC3E8 /* AppleScriptTest.m in Sources */,
A6C763FE1B45C72F00E3C992 /* iTermTests.m in Sources */,
A6D22A441BC8BE6B004084E0 /* Model.xcdatamodeld in Sources */,
Loading
Loading
@@ -8835,6 +8840,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A68AC8F71F0823100023A216 /* iTermFindOnPageHelperTest.m in Sources */,
A6BDB04A1B45EBD900F511E6 /* VT100CSIParserTest.m in Sources */,
A66B71231C826F4500D461E2 /* iTermTextExtractorTest.m in Sources */,
A6BDB0481B45EB7F00F511E6 /* iTermIntervalTreeTest.m in Sources */,
//
// iTermFindOnPageHelperTest.m
// iTerm2
//
// Created by George Nachman on 7/1/17.
//
//
#import <XCTest/XCTest.h>
#import "iTermFindOnPageHelper.h"
#import "FindContext.h"
#import "SearchResult.h"
@interface iTermFindOnPageHelperTest : XCTestCase
@end
@implementation iTermFindOnPageHelperTest{
FindContext *findContext;
iTermFindOnPageHelper *helper;
}
- (void)setUp {
findContext = [[[FindContext alloc] init] autorelease];
helper = [[[iTermFindOnPageHelper alloc] init] autorelease];
[helper findString:@"test"
forwardDirection:NO
mode:iTermFindModeCaseInsensitiveSubstring
withOffset:0
context:findContext
numberOfLines:100
totalScrollbackOverflow:0];
}
- (void)testFindRangeOfSearchResults_Random {
for (int j = 0; j < 10000; j++) {
srand(j);
findContext = [[[FindContext alloc] init] autorelease];
helper = [[[iTermFindOnPageHelper alloc] init] autorelease];
[helper findString:@"test"
forwardDirection:NO
mode:iTermFindModeCaseInsensitiveSubstring
withOffset:0
context:findContext
numberOfLines:100
totalScrollbackOverflow:0];
int x = 0;
int n = 1 + rand() % 23;
NSMutableArray<NSNumber *> *values = [NSMutableArray array];
for (int i = 0; i < n; i++) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = rand() % 20;
r.startX = x++;
[values addObject:@(r.absStartY)];
[helper addSearchResult:r width:80];
}
[values sortUsingComparator:^NSComparisonResult(NSNumber * _Nonnull obj1, NSNumber * _Nonnull obj2) {
return [obj2 compare:obj1];
}];
for (int k = 0; k < 100; k++) {
NSRange range = NSMakeRange(rand() % 30, rand() % 30);
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:range];
NSRange expected = NSMakeRange(NSNotFound, 0);
for (int i = 0; i < values.count; i++) {
if (values[i].integerValue < NSMaxRange(range)) {
expected.location = i;
break;
}
}
if (expected.location != NSNotFound) {
for (int i = values.count - 1; i >= 0; i--) {
if (values[i].integerValue >= range.location) {
expected.length = i - expected.location + 1;
break;
}
}
if (expected.length == 0) {
expected.location = NSNotFound;
}
}
XCTAssertTrue(NSEqualRanges(actual, expected), @"Unequal ranges for values %@ and query location=%@ length=%@. Actual=%@, expected=%@",
values, @(range.location), @(range.length), NSStringFromRange(actual), NSStringFromRange(expected));
}
}
}
- (void)testFindRangeOfSearchResults_Basic {
for (NSNumber *y in @[ @10, @20, @30, @35, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(30, 11)];
NSRange expected = NSMakeRange(2, 3);
XCTAssertTrue(NSEqualRanges(actual, expected));
}
- (void)testFindRangeOfSearchResults_MultiMin {
int x = 0;
for (NSNumber *y in @[ @10, @20, @30, @30, @30, @35, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
r.startX = x++;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(30, 11)];
NSRange expected = NSMakeRange(2, 5);
XCTAssertTrue(NSEqualRanges(actual, expected));
}
- (void)testFindRangeOfSearchResults_MultiMax {
int x = 0;
for (NSNumber *y in @[ @10, @20, @30, @35, @40, @40, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
r.startX = x++;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(30, 11)];
NSRange expected = NSMakeRange(2, 5);
XCTAssertTrue(NSEqualRanges(actual, expected));
}
- (void)testFindRangeOfSearchResults_InexactMin {
for (NSNumber *y in @[ @10, @20, @30, @35, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(25, 11)];
NSRange expected = NSMakeRange(3, 2);
XCTAssertTrue(NSEqualRanges(actual, expected));
}
- (void)testFindRangeOfSearchResults_InexactMax {
for (NSNumber *y in @[ @10, @20, @30, @35, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(30, 15)];
NSRange expected = NSMakeRange(2, 3);
XCTAssertTrue(NSEqualRanges(actual, expected));
}
- (void)testFindRangeOfSearchResults_NoResults {
for (NSNumber *y in @[ @10, @20, @30, @35, @40, @50, @60 ]) {
SearchResult *r = [[[SearchResult alloc] init] autorelease];
r.absStartY = y.integerValue;
[helper addSearchResult:r width:80];
}
NSRange actual = [helper rangeOfSearchResultsInRangeOfLines:NSMakeRange(11, 5)];
XCTAssertEqual(actual.length, 0);
}
@end
Loading
Loading
@@ -74,7 +74,7 @@ typedef NS_ENUM(NSUInteger, iTermFindMode) {
- (void)findViewControllerMakeDocumentFirstResponder;
 
// Remove highlighted matches
- (void)clearHighlights;
- (void)findViewControllerClearSearch;
 
// Preform a search
- (void)findString:(NSString *)aString
Loading
Loading
Loading
Loading
@@ -344,7 +344,7 @@ const CGFloat kEdgeWidth = 3;
[[[self view] animator] setFrame:[self collapsedFrame]];
[NSAnimationContext endGrouping];
 
[delegate_ clearHighlights];
[delegate_ findViewControllerClearSearch];
[delegate_ findViewControllerMakeDocumentFirstResponder];
}
 
Loading
Loading
@@ -471,7 +471,7 @@ const CGFloat kEdgeWidth = 3;
BOOL ok = NO;
if ([delegate_ canSearch]) {
if ([subString length] <= 0) {
[delegate_ clearHighlights];
[delegate_ findViewControllerClearSearch];
} else {
[delegate_ findString:subString
forwardDirection:direction
Loading
Loading
Loading
Loading
@@ -1512,8 +1512,12 @@ ITERM_WEAKLY_REFERENCEABLE
DLog(@"Set session %@ to %@", self, VT100GridSizeDescription(size));
[_screen setSize:size];
[_shell setSize:size];
[_textview clearHighlights];
[_textview clearHighlights:NO];
[[_delegate realParentWindow] invalidateRestorableState];
if (!_tailFindTimer &&
[_delegate sessionBelongsToVisibleTab]) {
[self beginTailFind];
}
}
 
- (void)setSplitSelectionMode:(SplitSelectionMode)mode move:(BOOL)move {
Loading
Loading
@@ -4729,9 +4733,8 @@ ITERM_WEAKLY_REFERENCEABLE
[self takeFocus];
}
 
- (void)clearHighlights
{
[_textview clearHighlights];
- (void)findViewControllerClearSearch {
[_textview clearHighlights:YES];
}
 
- (NSImage *)snapshot {
Loading
Loading
@@ -7368,7 +7371,7 @@ ITERM_WEAKLY_REFERENCEABLE
}
 
- (void)screenClearHighlights {
[_textview clearHighlights];
[_textview clearHighlights:NO];
}
 
- (void)screenMouseModeDidChange {
Loading
Loading
Loading
Loading
@@ -434,7 +434,10 @@ typedef void (^PTYTextViewDrawingHookBlock)(iTermTextDrawingHelper *);
withOffset:(int)offset;
 
// Remove highlighted terms from previous search.
- (void)clearHighlights;
// If resetContext is set then the search state will get reset to empty.
// Otherwise, search results and highlights are removed and can be updated
// on the next search.
- (void)clearHighlights:(BOOL)resetContext;
 
// Performs a find on the next chunk of text.
- (BOOL)continueFind:(double *)progress;
Loading
Loading
Loading
Loading
@@ -5530,9 +5530,13 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
totalScrollbackOverflow:[_dataSource totalScrollbackOverflow]];
}
 
- (void)clearHighlights {
- (void)clearHighlights:(BOOL)resetContext {
[_findOnPageHelper clearHighlights];
[_findOnPageHelper resetCopiedFindContext];
if (resetContext) {
[_findOnPageHelper resetCopiedFindContext];
} else {
[_findOnPageHelper removeAllSearchResults];
}
}
 
- (void)setTransparency:(double)fVal {
Loading
Loading
@@ -6592,6 +6596,7 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
if (range.length > 0) {
foundDirty = YES;
[_findOnPageHelper removeHighlightsInRange:NSMakeRange(y + totalScrollbackOverflow, 1)];
[_findOnPageHelper removeSearchResultsInRange:NSMakeRange(y + totalScrollbackOverflow, 1)];
[self setNeedsDisplayOnLine:y inRange:range];
}
}
Loading
Loading
Loading
Loading
@@ -55,6 +55,7 @@
@property(nonatomic, readonly) BOOL haveFindCursor;
@property(nonatomic, readonly) VT100GridAbsCoord findCursorAbsCoord;
@property(nonatomic, readonly) FindContext *copiedContext;
@property(nonatomic, readonly) NSOrderedSet<SearchResult *> *searchResults;
 
// Begin a new search.
//
Loading
Loading
@@ -98,8 +99,12 @@ totalScrollbackOverflow:(long long)totalScrollbackOverflow;
 
// Remove highlights in a range of lines.
- (void)removeHighlightsInRange:(NSRange)range;
- (void)removeSearchResultsInRange:(NSRange)range;
- (void)removeAllSearchResults;
 
// Sets the location to start searching. TODO: Currently this only works for find next/prev.
- (void)setStartPoint:(VT100GridAbsCoord)startPoint;
 
- (NSRange)rangeOfSearchResultsInRangeOfLines:(NSRange)range;
@end
Loading
Loading
@@ -360,6 +360,75 @@
}
}
 
- (NSInteger)smallestIndexOfLastSearchResultWithYLessThan:(NSInteger)query {
SearchResult *querySearchResult = [[[SearchResult alloc] init] autorelease];
querySearchResult.absStartY = query;
NSInteger index = [_searchResults indexOfObject:querySearchResult
inSortedRange:NSMakeRange(0, _searchResults.count)
options:(NSBinarySearchingInsertionIndex | NSBinarySearchingFirstEqual)
usingComparator:^NSComparisonResult(SearchResult * _Nonnull obj1, SearchResult * _Nonnull obj2) {
return [@(obj2.absStartY) compare:@(obj1.absStartY)];
}];
if (index == _searchResults.count) {
index--;
}
while (_searchResults[index].absStartY >= query) {
if (index + 1 == _searchResults.count) {
return NSNotFound;
}
index++;
}
return index;
}
- (NSInteger)largestIndexOfSearchResultWithYGreaterThanOrEqualTo:(NSInteger)query {
SearchResult *querySearchResult = [[[SearchResult alloc] init] autorelease];
querySearchResult.absStartY = query;
NSInteger index = [_searchResults indexOfObject:querySearchResult
inSortedRange:NSMakeRange(0, _searchResults.count)
options:(NSBinarySearchingInsertionIndex | NSBinarySearchingLastEqual)
usingComparator:^NSComparisonResult(SearchResult * _Nonnull obj1, SearchResult * _Nonnull obj2) {
return [@(obj2.absStartY) compare:@(obj1.absStartY)];
}];
if (index == _searchResults.count) {
index--;
}
while (_searchResults[index].absStartY < query) {
if (index == 0) {
return NSNotFound;
}
index--;
}
return index;
}
- (NSRange)rangeOfSearchResultsInRangeOfLines:(NSRange)range {
if (_searchResults.count == 0) {
return NSMakeRange(NSNotFound, 0);
}
NSInteger tailIndex = [self largestIndexOfSearchResultWithYGreaterThanOrEqualTo:range.location];
if (tailIndex == NSNotFound) {
return NSMakeRange(NSNotFound, 0);
}
NSInteger headIndex = [self smallestIndexOfLastSearchResultWithYLessThan:NSMaxRange(range)];
if (tailIndex < headIndex) {
return NSMakeRange(NSNotFound, 0);
} else {
return NSMakeRange(headIndex, tailIndex - headIndex + 1);
}
}
- (void)removeAllSearchResults {
[_searchResults removeAllObjects];
}
- (void)removeSearchResultsInRange:(NSRange)range {
NSRange objectRange = [self rangeOfSearchResultsInRangeOfLines:range];
if (objectRange.location != NSNotFound && objectRange.length > 0) {
[_searchResults removeObjectsInRange:objectRange];
}
}
- (void)setStartPoint:(VT100GridAbsCoord)startPoint {
_findCursor = startPoint;
}
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment