Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search and replace with '&' to match search text. #949

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Documents/Users/FeatureList.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ The layout is forced to change with Ctrl-w,s or Ctrl-w,v .

Regex search is supported using the [ICU regex](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html) format.

Search and replace using matched string(&) in the replacement text is supported:

Applying `:%s/foo/&bar/` to `foo bar` gives `foobar bar`

## Insert mode commands

C-y, C-e
Expand Down
1 change: 1 addition & 0 deletions XVim/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<string>1</string>
<key>DVTPlugInCompatibilityUUIDs</key>
<array>
<string>ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C</string>
<string>AD68E85B-441B-4301-B564-A45E4919A6AD</string>
<string>A2E4D43F-41F4-4FB9-BB94-7177011C9AED</string>
<string>37B30044-3B14-46BA-ABAA-F01000C27B63</string>
Expand Down
6 changes: 6 additions & 0 deletions XVim/Test/XVimTester+Search.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ - (NSArray*)search_testcases{
static NSString* replace11_result = @"aaa ddd ccc\n"
@"aaa.ddd.ccc\n\n";

static NSString* replace12_result = @"aaa bbbbb ccc\n"
@"bbbbb ccc ccc\n\n";
return [NSArray arrayWithObjects:
//
// replace(:s)
Expand All @@ -107,6 +109,9 @@ - (NSArray*)search_testcases{
XVimMakeTestCase(text6, 0, 0, @"Vj:s/$/fffff/g<CR>", replace7_result, 32, 0),
// $, two
XVimMakeTestCase(text7, 0, 0, @"Vj:s/$/fffff/g<CR>", replace8_result, 32, 0),

XVimMakeTestCase(text7, 0, 0, @":%s/bbb/&bb/g<CR>", replace12_result, 19, 0),
XVimMakeTestCase(text7, 0, 0, @":%s/bb/&bb/g<CR>", replace12_result, 18, 0),

// c, quit
XVimMakeTestCase(text6, 0, 0, @"Vj:s/ccc/eeeee/gc<CR>q", text6, 8, 0),
Expand Down Expand Up @@ -205,6 +210,7 @@ - (NSArray*)search_testcases{

// search followed by implicit replace. added to cover https://github.com/XVimProject/XVim/issues/730
XVimMakeTestCase(text8, 0, 0, @":set vimregex<CR>/bbb<CR>:%s//ddd/g<CR>", replace11_result, 19, 0),

nil];
}
@end
33 changes: 24 additions & 9 deletions XVim/XVimSearch.m
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,11 @@ - (void)substitute:(NSString*)ex_command from:(NSUInteger)from to:(NSUInteger)to
}
}

- (void)updateStartLocationInWindow:(XVimWindow*)window
- (void)updateStartLocationInWindow:(XVimWindow*)window replacementString:(NSString*)replacementString
{
// global option on; consider all matches on each line
if (self.isGlobal) {
self.replaceStartLocation = self.lastFoundRange.location + self.lastReplacementString.length;
self.replaceStartLocation = self.lastFoundRange.location + replacementString.length;

// If search string contained a $, move to the next line
if ([self.lastSearchCmd rangeOfString:@"$"].length > 0) {
Expand All @@ -539,22 +539,37 @@ - (void)updateStartLocationInWindow:(XVimWindow*)window
}
}

- (void) updateEndLocationInWindow:(XVimWindow*)window
- (void) updateEndLocationInWindow:(XVimWindow*)windo replacementString:(NSString*)replacementString
{
self.replaceEndLocation += ([self.lastReplacementString length] - self.lastFoundRange.length);
self.replaceEndLocation += ([replacementString length] - self.lastFoundRange.length);
}

- (void)replaceCurrentInWindow:(XVimWindow*)window findNext:(BOOL)findNext
{
NSTextView* srcView = [window sourceView];

NSString *textToReplace = [[srcView string] substringWithRange:self.lastFoundRange];
NSString *replacementString = self.lastReplacementString;
NSArray *splitsOnEscapedAmpersands = [replacementString componentsSeparatedByString:@"\\&"];
NSMutableArray *stringsToJoin = [[NSMutableArray alloc] init];

for (NSString* stringWithoutEscapedAmpersands in splitsOnEscapedAmpersands) {
NSArray *splitsOnAmpersands = [stringWithoutEscapedAmpersands componentsSeparatedByString:@"&"];
NSString *springsWithMatch = [splitsOnAmpersands componentsJoinedByString:textToReplace];
[stringsToJoin addObject:springsWithMatch];
}

[srcView insertText:self.lastReplacementString replacementRange:self.lastFoundRange];
[srcView xvim_moveCursor:self.lastFoundRange.location + self.lastReplacementString.length preserveColumn:NO];
if ([stringsToJoin count] > 0) {
replacementString = [stringsToJoin componentsJoinedByString:@"\\&"];
}

[srcView insertText:replacementString replacementRange:self.lastFoundRange];
[srcView xvim_moveCursor:self.lastFoundRange.location + replacementString.length preserveColumn:NO];
self.numReplacements++;

if (findNext) {
[self updateStartLocationInWindow:window];
[self updateEndLocationInWindow:window];
[self updateStartLocationInWindow:window replacementString:replacementString];
[self updateEndLocationInWindow:window replacementString:replacementString];
[self findForwardFrom:self.replaceStartLocation to:self.replaceEndLocation inWindow:window];
}
else {
Expand All @@ -578,7 +593,7 @@ - (void)replaceCurrentToEndInWindow:(XVimWindow*)window
[srcView insertText:self.lastReplacementString replacementRange:self.lastFoundRange];
self.numReplacements++;

[self updateEndLocationInWindow:window];
[self updateEndLocationInWindow:window replacementString:self.lastReplacementString];
[self findForwardFrom:self.replaceStartLocation to:self.replaceEndLocation inWindow:window];
} while (self.lastFoundRange.location != NSNotFound);
[self showStatusIfDoneInWindow:window];
Expand Down