Skip to content

feat(language-core): improve support for range mapping#206

Closed
piotrtomiak wants to merge 8 commits intovolarjs:masterfrom
piotrtomiak:overlapping-ranges
Closed

feat(language-core): improve support for range mapping#206
piotrtomiak wants to merge 8 commits intovolarjs:masterfrom
piotrtomiak:overlapping-ranges

Conversation

@piotrtomiak
Copy link
Contributor

@piotrtomiak piotrtomiak commented Jun 19, 2024

Fixes #203

break;
}

for (const [mapped] of map.getGeneratedOffsets(start, filter)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter is added to map API, to optimize iterations and disregard mappings early on

});

it('overlapping ranges', () => {
const mappings: Mapping<CodeInformation>[] = [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overlapping ranges actually work, they just need to be in separate mappings

const memo = this.getMemoBasedOnRange(fromRange);
if (memo.offsets.length === 0) {
return;
* findMatchingStartEnd(start: number, end: number, fromRange: CodeRangeKey, filter?: (data: Data) => boolean): Generator<[start: number, end: number, Mapping<Data>]> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've encapsulated all of the range mapping logic here. The main idea is to not take the first mapping possible, but look for the one which fits the range the best, i.e. is the shortest possible.


}

class BinarySearchStorage<Data> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've originally had the interval storage here, which turned out to be inefficient and not really needed anyway, so I kept the logic in the separate class.

const fromLength = fromLengths[mid];

if (offset >= fromOffset && offset <= fromOffset + fromLength) {
yield [mapping, mid]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main difference is that we don't return offset, but the mapping with range index. This allows us to find ranges which contain both start an end and prefer them.

}
}

export function areRangesSortedAndNonOverlapping(offsets: number[], lenghts: number[]): boolean {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little bit stricter check - no overlapping allowed within a particular mapping

const generateEnd = toGeneratedOffset(language, serviceScript, sourceScript, end, isFormattingEnabled);
if (generateStart !== undefined && generateEnd !== undefined) {
const edits = getFormattingEditsForRange(targetScript.id, generateStart, generateEnd, options);
const generatedRange = toGeneratedRange(language, serviceScript, sourceScript, { pos: start, end }, isCodeActionsEnabled);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use range

else {
for (const [generatedStart, generatedEnd] of toGeneratedRanges(language, serviceScript, sourceScript, positionOrRange.pos, positionOrRange.end, isCodeActionsEnabled)) {
return getApplicableRefactors(targetScript.id, { pos: generatedStart, end: generatedEnd }, preferences, triggerReason, kind, includeInteractiveActions);
for (const generatedRange of toGeneratedRanges(language, serviceScript, sourceScript, positionOrRange, isCodeActionsEnabled)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed API of toGenerateRanges to return a range object

johnsoncodehk added a commit that referenced this pull request Jun 20, 2024
Co-Authored-By: Piotr Tomiak <piotr.tomiak@gmail.com>
johnsoncodehk added a commit that referenced this pull request Jun 20, 2024
Co-Authored-By: Piotr Tomiak <piotr.tomiak@gmail.com>
@piotrtomiak
Copy link
Contributor Author

Hi! I've added some refinements to the startEnd matching logic. It is more readable now and also it supports the fallback mode out-of-the-box.

johnsoncodehk added a commit that referenced this pull request Jun 21, 2024
Co-Authored-By: Piotr Tomiak <piotr.tomiak@gmail.com>
@johnsoncodehk
Copy link
Member

Since overlapping mapping handling is Angular-specific behavior, I think it's best to keep this implementation in WebStorm-Angular and keep the default implementation simple.

#207 Added a method to make mapping logic customizable, can you check if it meets your needs?

@piotrtomiak
Copy link
Contributor Author

@johnsoncodehk - sounds good! I've copy/paste my implementation of source map to angular plugin and it works fine! Thanks for the changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support overlapping mapping ranges

2 participants