Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit d4bcc42

Browse files
authored
Merge pull request #1085 from atom/ripgrep-option
Handle multiline results on the find and replace UI
2 parents ec58b34 + e2600aa commit d4bcc42

File tree

2 files changed

+71
-29
lines changed

2 files changed

+71
-29
lines changed

lib/project-find-view.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ class ProjectFindView {
318318
return searchPromise;
319319
}
320320

321-
search(options) {
321+
async search(options) {
322322
// We always want to set the options passed in, even if we dont end up doing the search
323323
if (options == null) { options = {}; }
324324
this.model.getFindOptions().set(options);
@@ -330,13 +330,13 @@ class ProjectFindView {
330330
let {onlyRunIfActive, onlyRunIfChanged} = options;
331331
if ((onlyRunIfActive && !this.model.active) || !findPattern) return Promise.resolve();
332332

333-
return this.showResultPane().then(() => {
334-
try {
335-
return this.model.search(findPattern, pathsPattern, replacePattern, options);
336-
} catch (e) {
337-
this.setErrorMessage(e.message);
338-
}
339-
});
333+
await this.showResultPane()
334+
335+
try {
336+
return await this.model.search(findPattern, pathsPattern, replacePattern, options);
337+
} catch (e) {
338+
this.setErrorMessage(e.message);
339+
}
340340
}
341341

342342
replaceAll() {

lib/project/results-model.js

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,57 @@ const escapeHelper = require('../escape-helper')
55
class Result {
66
static create (result) {
77
if (result && result.matches && result.matches.length) {
8-
const matches = result.matches.map(m =>
9-
({
10-
matchText: m.matchText,
11-
lineText: m.lineText,
12-
lineTextOffset: m.lineTextOffset,
13-
range: Range.fromObject(m.range),
14-
leadingContextLines: m.leadingContextLines,
15-
trailingContextLines: m.trailingContextLines
16-
})
17-
)
8+
const matches = []
9+
10+
for (const m of result.matches) {
11+
const range = Range.fromObject(m.range)
12+
const matchSplit = m.matchText.split('\n')
13+
const linesSplit = m.lineText.split('\n')
14+
15+
// If the result spans across multiple lines, process each of
16+
// them separately by creating separate `matches` objects for
17+
// each line on the match.
18+
for (let row = range.start.row; row <= range.end.row; row++) {
19+
const lineText = linesSplit[row - range.start.row]
20+
const matchText = matchSplit[row - range.start.row]
21+
22+
// When receiving multiline results from opened buffers, only
23+
// the first result line is provided on the `lineText` property.
24+
// This makes it impossible to properly render the part of the result
25+
// that's part of other lines.
26+
// In order to prevent an error we just need to ignore these parts.
27+
if (lineText === undefined || matchText === undefined) {
28+
continue
29+
}
30+
31+
// Adapt the range column number based on which line we're at:
32+
// - the first line of a multiline result will always start at the range start
33+
// and will end at the end of the line.
34+
// - middle lines will start at 0 and end at the end of the line
35+
// - last line will start at 0 and end at the range end.
36+
const startColumn = row === range.start.row ? range.start.column : 0
37+
const endColumn = row === range.end.row ? range.end.column : lineText.length
38+
39+
matches.push({
40+
matchText,
41+
lineText,
42+
lineTextOffset: m.lineTextOffset,
43+
range: {
44+
start: {
45+
row,
46+
column: startColumn
47+
},
48+
end: {
49+
row,
50+
column: endColumn
51+
}
52+
},
53+
leadingContextLines: m.leadingContextLines,
54+
trailingContextLines: m.trailingContextLines
55+
})
56+
}
57+
}
58+
1859
return new Result({filePath: result.filePath, matches})
1960
} else {
2061
return null
@@ -146,7 +187,7 @@ module.exports = class ResultsModel {
146187
)
147188
}
148189

149-
search (findPattern, pathsPattern, replacePattern, options = {}) {
190+
async search (findPattern, pathsPattern, replacePattern, options = {}) {
150191
if (!this.shouldRerunSearch(findPattern, pathsPattern, options)) {
151192
this.emitter.emit('did-noop-search')
152193
return Promise.resolve()
@@ -195,17 +236,18 @@ module.exports = class ResultsModel {
195236
})
196237

197238
this.emitter.emit('did-start-searching', this.inProgressSearchPromise)
198-
return this.inProgressSearchPromise.then(message => {
199-
if (message === 'cancelled') {
200-
this.emitter.emit('did-cancel-searching')
201-
} else {
202-
const resultsSummary = this.getResultsSummary()
203239

204-
this.metricsReporter.sendSearchEvent(Date.now() - startTime, resultsSummary.matchCount)
205-
this.inProgressSearchPromise = null
206-
this.emitter.emit('did-finish-searching', resultsSummary)
207-
}
208-
})
240+
const message = await this.inProgressSearchPromise
241+
242+
if (message === 'cancelled') {
243+
this.emitter.emit('did-cancel-searching')
244+
} else {
245+
const resultsSummary = this.getResultsSummary()
246+
247+
this.metricsReporter.sendSearchEvent(Date.now() - startTime, resultsSummary.matchCount)
248+
this.inProgressSearchPromise = null
249+
this.emitter.emit('did-finish-searching', resultsSummary)
250+
}
209251
}
210252

211253
replace (pathsPattern, replacePattern, replacementPaths) {

0 commit comments

Comments
 (0)