|
7 | 7 | TextEditor,
|
8 | 8 | next,
|
9 | 9 | } from "@cursorless/common";
|
| 10 | +import { zip } from "itertools"; |
10 | 11 | import { ScopeHandlerFactory } from ".";
|
| 12 | +import { Target } from "../../../typings/target.types"; |
11 | 13 | import { createContinuousRangeTarget } from "../../createContinuousRangeTarget";
|
12 | 14 | import { BaseScopeHandler } from "./BaseScopeHandler";
|
13 | 15 | import type { TargetScope } from "./scope.types";
|
@@ -85,24 +87,23 @@ function combineScopes(scope1: TargetScope, scope2: TargetScope): TargetScope {
|
85 | 87 | editor: scope1.editor,
|
86 | 88 | domain: scope1.domain.union(scope2.domain),
|
87 | 89 | getTargets: (isReversed) => {
|
88 |
| - const target1 = scope1.getTargets(isReversed)[0]; |
89 |
| - const target2 = scope2.getTargets(isReversed)[0]; |
90 |
| - |
91 |
| - const [startTarget, endTarget] = target1.contentRange.start.isBefore( |
92 |
| - target2.contentRange.start, |
93 |
| - ) |
94 |
| - ? [target1, target2] |
95 |
| - : [target2, target1]; |
96 |
| - |
97 |
| - return [ |
98 |
| - createContinuousRangeTarget( |
| 90 | + return zip( |
| 91 | + scope1.getTargets(isReversed), |
| 92 | + scope2.getTargets(isReversed), |
| 93 | + ).map(([target1, target2]) => { |
| 94 | + const [startTarget, endTarget] = getTargetsInDocumentOrder( |
| 95 | + target1, |
| 96 | + target2, |
| 97 | + ); |
| 98 | + |
| 99 | + return createContinuousRangeTarget( |
99 | 100 | isReversed,
|
100 | 101 | startTarget,
|
101 | 102 | endTarget,
|
102 | 103 | true,
|
103 | 104 | true,
|
104 |
| - ), |
105 |
| - ]; |
| 105 | + ); |
| 106 | + }); |
106 | 107 | },
|
107 | 108 | };
|
108 | 109 | }
|
@@ -145,34 +146,41 @@ function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean {
|
145 | 146 | return true;
|
146 | 147 | }
|
147 | 148 |
|
148 |
| - const target1 = scope1.getTargets(false)[0]; |
149 |
| - const target2 = scope2.getTargets(false)[0]; |
150 |
| - |
151 |
| - const [leadingTarget, trailingTarget] = target1.contentRange.start.isBefore( |
152 |
| - target2.contentRange.start, |
153 |
| - ) |
154 |
| - ? [target1, target2] |
155 |
| - : [target2, target1]; |
| 149 | + const [startTarget, endTarget] = getTargetsInDocumentOrder( |
| 150 | + scope1.getTargets(false)[0], |
| 151 | + scope2.getTargets(false)[0], |
| 152 | + ); |
156 | 153 |
|
157 | 154 | const leadingRange =
|
158 |
| - leadingTarget.getTrailingDelimiterTarget()?.contentRange ?? |
159 |
| - leadingTarget.contentRange; |
| 155 | + startTarget.getTrailingDelimiterTarget()?.contentRange ?? |
| 156 | + startTarget.contentRange; |
160 | 157 | const trailingRange =
|
161 |
| - trailingTarget.getLeadingDelimiterTarget()?.contentRange ?? |
162 |
| - trailingTarget.contentRange; |
| 158 | + endTarget.getLeadingDelimiterTarget()?.contentRange ?? |
| 159 | + endTarget.contentRange; |
163 | 160 |
|
164 | 161 | if (leadingRange.intersection(trailingRange) != null) {
|
165 | 162 | return true;
|
166 | 163 | }
|
167 | 164 |
|
| 165 | + // Non line targets are excluded if they are separated by more than one line |
168 | 166 | if (
|
169 |
| - !leadingTarget.isLine && |
| 167 | + !startTarget.isLine && |
170 | 168 | trailingRange.start.line - leadingRange.end.line > 1
|
171 | 169 | ) {
|
172 | 170 | return false;
|
173 | 171 | }
|
174 | 172 |
|
| 173 | + // Finally targets are excluded if there is non whitespace text between them |
175 | 174 | const rangeBetween = new Range(leadingRange.end, trailingRange.start);
|
176 |
| - const text = leadingTarget.editor.document.getText(rangeBetween); |
| 175 | + const text = startTarget.editor.document.getText(rangeBetween); |
177 | 176 | return /^\s*$/.test(text);
|
178 | 177 | }
|
| 178 | + |
| 179 | +function getTargetsInDocumentOrder( |
| 180 | + target1: Target, |
| 181 | + target2: Target, |
| 182 | +): [Target, Target] { |
| 183 | + return target1.contentRange.start.isBefore(target2.contentRange.start) |
| 184 | + ? [target1, target2] |
| 185 | + : [target2, target1]; |
| 186 | +} |
0 commit comments