|
1 | 1 | const getIconServices = require('../get-icon-services');
|
2 |
| -const { Range } = require('atom'); |
| 2 | +const { Point, Range } = require('atom'); |
3 | 3 | const {
|
4 | 4 | LeadingContextRow,
|
5 | 5 | TrailingContextRow,
|
@@ -111,57 +111,104 @@ class MatchRowView {
|
111 | 111 | }
|
112 | 112 |
|
113 | 113 | generatePreviewNode({matches, replacePattern, regex}) {
|
114 |
| - const subnodes = []; |
| 114 | + const TYPE = { |
| 115 | + MATCH: 1, |
| 116 | + TEXT: 2, |
| 117 | + ELLIPSIS: 3 |
| 118 | + }; |
| 119 | + |
| 120 | + const segments = []; |
115 | 121 |
|
116 |
| - let prevMatchEnd = matches[0].lineTextOffset; |
117 | 122 | for (const match of matches) {
|
118 |
| - const range = Range.fromObject(match.range); |
119 |
| - const prefixStart = Math.max(0, prevMatchEnd - match.lineTextOffset); |
120 |
| - const matchStart = range.start.column - match.lineTextOffset; |
| 123 | + if (segments.length) { |
| 124 | + const previousRange = segments[segments.length - 1].range; |
| 125 | + const currentRange = new Range( |
| 126 | + new Point(0, match.lineTextOffset), |
| 127 | + new Point(0, match.lineTextOffset + match.lineText.length) |
| 128 | + ); |
| 129 | + |
| 130 | + if (previousRange.intersectsWith(currentRange)) { |
| 131 | + const segment = segments.pop(); |
| 132 | + // current range starts before previous range, therefore it should contain everything from previous range |
| 133 | + if (previousRange.start.isGreaterThanOrEqual(currentRange.start)) { |
| 134 | + // Delete everything up to previous match from the beginning of current range |
| 135 | + match.lineText = match.lineText.substring(previousRange.start.column - currentRange.start.column); |
| 136 | + match.lineTextOffset = previousRange.start.column; |
| 137 | + } else { // current range starts midway through previous range |
| 138 | + // Prepend non-overlapping part of previous range to current range |
| 139 | + const preprefix = segment.content.substring(0, currentRange.start.column - previousRange.start.column); |
| 140 | + match.lineText = preprefix + match.lineText; |
| 141 | + match.lineTextOffset -= preprefix.length; |
| 142 | + } |
| 143 | + } else { // current range does not intersect and comes after previous range |
| 144 | + segments.push({ type: TYPE.ELLIPSIS, range: new Range(previousRange.end, currentRange.start) }); |
| 145 | + } |
| 146 | + } |
121 | 147 |
|
122 |
| - // TODO - Handle case where (prevMatchEnd < match.lineTextOffset) |
123 |
| - // The solution probably needs Workspace.scan to be reworked to account |
124 |
| - // for multiple matches lines first |
| 148 | + const prefix = match.lineText.substring(0, match.range.start.column - match.lineTextOffset); |
| 149 | + const suffix = match.lineText.substring(match.range.end.column - match.lineTextOffset); |
125 | 150 |
|
126 |
| - const prefix = match.lineText.slice(prefixStart, matchStart); |
| 151 | + if (prefix) { |
| 152 | + segments.push({ |
| 153 | + type: TYPE.TEXT, |
| 154 | + content: prefix, |
| 155 | + range: new Range( |
| 156 | + new Point(0, match.lineTextOffset), |
| 157 | + new Point(0, match.range.start.column) |
| 158 | + ) |
| 159 | + }); |
| 160 | + } |
127 | 161 |
|
128 |
| - let replacementText = '' |
129 |
| - if (replacePattern && regex) { |
130 |
| - replacementText = match.matchText.replace(regex, replacePattern); |
131 |
| - } else if (replacePattern) { |
132 |
| - replacementText = replacePattern; |
| 162 | + let replacementText |
| 163 | + if (replacePattern) { |
| 164 | + replacementText = regex ? match.matchText.replace(regex, replacePattern) : replacePattern; |
133 | 165 | }
|
134 | 166 |
|
135 |
| - subnodes.push( |
136 |
| - $.span({}, prefix), |
137 |
| - $.span( |
138 |
| - { |
139 |
| - className: |
140 |
| - `match ${replacementText ? 'highlight-error' : 'highlight-info'}` |
141 |
| - }, |
142 |
| - match.matchText |
| 167 | + segments.push({ |
| 168 | + type: TYPE.MATCH, |
| 169 | + content: match.matchText, |
| 170 | + range: new Range( |
| 171 | + new Point(0, match.range.start.column), |
| 172 | + new Point(0, match.range.end.column) |
143 | 173 | ),
|
144 |
| - $.span( |
145 |
| - { |
146 |
| - className: 'replacement highlight-success', |
147 |
| - style: showIf(replacementText) |
148 |
| - }, |
149 |
| - replacementText |
150 |
| - ) |
151 |
| - ); |
152 |
| - prevMatchEnd = range.end.column; |
| 174 | + replacement: replacementText |
| 175 | + }); |
| 176 | + |
| 177 | + if (suffix) { |
| 178 | + segments.push({ |
| 179 | + type: TYPE.TEXT, |
| 180 | + content: suffix, |
| 181 | + range: new Range( |
| 182 | + new Point(0, match.range.end.column), |
| 183 | + new Point(0, match.lineTextOffset + match.lineText.length) |
| 184 | + ) |
| 185 | + }); |
| 186 | + } |
153 | 187 | }
|
154 | 188 |
|
155 |
| - const lastMatch = matches[matches.length - 1]; |
156 |
| - const suffix = lastMatch.lineText.slice( |
157 |
| - prevMatchEnd - lastMatch.lineTextOffset |
158 |
| - ); |
| 189 | + const subnodes = []; |
159 | 190 |
|
160 |
| - return $.span( |
161 |
| - {className: 'preview'}, |
162 |
| - ...subnodes, |
163 |
| - $.span({}, suffix) |
164 |
| - ); |
| 191 | + for (const segment of segments) { |
| 192 | + if (segment.type === TYPE.TEXT) { |
| 193 | + subnodes.push($.span({}, segment.content)); |
| 194 | + } |
| 195 | + |
| 196 | + if (segment.type === TYPE.MATCH) { |
| 197 | + subnodes.push( |
| 198 | + $.span({ className: `match ${segment.replacement ? 'highlight-error' : 'highlight-info'}` }, segment.content) |
| 199 | + ); |
| 200 | + |
| 201 | + if (segment.replacement) { |
| 202 | + subnodes.push($.span({ className: 'replacement highlight-success' }, segment.replacement)); |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + if (segment.type === TYPE.ELLIPSIS) { |
| 207 | + subnodes.push($.span({}, '…')); |
| 208 | + } |
| 209 | + } |
| 210 | + |
| 211 | + return $.span({ className: 'preview' }, ...subnodes); |
165 | 212 | }
|
166 | 213 |
|
167 | 214 | render() {
|
|
0 commit comments