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

Support codeactions at the edges of tokens. #642

Merged
merged 1 commit into from
Jul 15, 2022
Merged
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
2 changes: 1 addition & 1 deletion src/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ export class Program {
//only keep diagnostics related to this file
.filter(x => x.file === file)
//only keep diagnostics that touch this range
.filter(x => util.rangesIntersect(x.range, range));
.filter(x => util.rangesIntersectOrTouch(x.range, range));

const scopes = this.getScopesForFile(file);

Expand Down
20 changes: 20 additions & 0 deletions src/bscPlugin/codeActions/CodeActionsProcessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,24 @@ describe('CodeActionsProcessor', () => {
testGetCodeActions(file, util.createRange(3, 34, 3, 34), [`import "pkg:/source/second.bs"`]);
});
});

it('suggests imports at very start and very end of diagnostic', () => {
program.setFile('source/first.bs', `
namespace alpha
function firstAction()
end function
end namespace
`);
program.setFile('components/MainScene.xml', trim`<component name="MainScene"></component>`);
const file = program.setFile('components/MainScene.bs', `
sub init()
print alpha.firstAction()
end sub
`);

// print |alpha.firstAction()
testGetCodeActions(file, util.createRange(2, 22, 2, 22), [`import "pkg:/source/first.bs"`]);
// print alpha|.firstAction()
testGetCodeActions(file, util.createRange(2, 27, 2, 27), [`import "pkg:/source/first.bs"`]);
});
});
106 changes: 106 additions & 0 deletions src/util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,22 @@ describe('util', () => {
});

describe('rangesIntersect', () => {
it('does not match when ranges do not touch (a < b)', () => {
// AA BB
expect(util.rangesIntersectOrTouch(
util.createRange(0, 0, 0, 1),
util.createRange(0, 2, 0, 3)
)).to.be.false;
});

it('does not match when ranges do not touch (a < b)', () => {
// BB AA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 2, 0, 3),
util.createRange(0, 0, 0, 1)
)).to.be.false;
});

it('does not match when ranges touch at right edge', () => {
// AABB
expect(util.rangesIntersect(
Expand Down Expand Up @@ -607,6 +623,96 @@ describe('util', () => {
});
});

describe('rangesIntersectOrTouch', () => {
it('does not match when ranges do not touch (a < b)', () => {
// AA BB
expect(util.rangesIntersectOrTouch(
util.createRange(0, 0, 0, 1),
util.createRange(0, 2, 0, 3)
)).to.be.false;
});

it('does not match when ranges do not touch (a < b)', () => {
// BB AA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 2, 0, 3),
util.createRange(0, 0, 0, 1)
)).to.be.false;
});

it('matches when ranges touch at right edge', () => {
// AABB
expect(util.rangesIntersectOrTouch(
util.createRange(0, 0, 0, 1),
util.createRange(0, 1, 0, 2)
)).to.be.true;
});

it('matches when ranges touch at left edge', () => {
// BBAA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 0, 2),
util.createRange(0, 0, 0, 1)
)).to.be.true;
});

it('matches when range overlaps by single character on the right', () => {
// A BA B
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 0, 3),
util.createRange(0, 2, 0, 4)
)).to.be.true;
});

it('matches when range overlaps by single character on the left', () => {
// B AB A
expect(util.rangesIntersectOrTouch(
util.createRange(0, 2, 0, 4),
util.createRange(0, 1, 0, 3)
)).to.be.true;
});

it('matches when A is contained by B at the edges', () => {
// B AA B
expect(util.rangesIntersectOrTouch(
util.createRange(0, 2, 0, 3),
util.createRange(0, 1, 0, 4)
)).to.be.true;
});

it('matches when B is contained by A at the edges', () => {
// A BB A
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 0, 4),
util.createRange(0, 2, 0, 3)
)).to.be.true;
});

it('matches when A and B are identical', () => {
// ABBA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 0, 2),
util.createRange(0, 1, 0, 2)
)).to.be.true;
});

it('matches when A spans multiple lines', () => {
// ABBA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 2, 0),
util.createRange(0, 1, 0, 3)
)).to.be.true;
});

it('matches when B spans multiple lines', () => {
// ABBA
expect(util.rangesIntersectOrTouch(
util.createRange(0, 1, 0, 3),
util.createRange(0, 1, 2, 0)
)).to.be.true;
});
});

it('sortByRange', () => {
const front = {
range: util.createRange(1, 1, 1, 2)
Expand Down
32 changes: 31 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,13 @@ export class Util {
}

/**
* Does a touch b in any way?
* Do `a` and `b` overlap by at least one character. This returns false if they are at the edges. Here's some examples:
* ```
* | true | true | true | true | true | false | false | false | false |
* |------|------|------|------|------|-------|-------|-------|-------|
* | aa | aaa | aaa | aaa | a | aa | aa | a | a |
* | bbb | bb | bbb | b | bbb | bb | bb | b | a |
* ```
*/
public rangesIntersect(a: Range, b: Range) {
// Check if `a` is before `b`
Expand All @@ -511,6 +517,30 @@ export class Util {
return true;
}

/**
* Do `a` and `b` overlap by at least one character or touch at the edges
* ```
* | true | true | true | true | true | true | true | false | false |
* |------|------|------|------|------|-------|-------|-------|-------|
* | aa | aaa | aaa | aaa | a | aa | aa | a | a |
* | bbb | bb | bbb | b | bbb | bb | bb | b | a |
* ```
*/
public rangesIntersectOrTouch(a: Range, b: Range) {
// Check if `a` is before `b`
if (a.end.line < b.start.line || (a.end.line === b.start.line && a.end.character < b.start.character)) {
return false;
}

// Check if `b` is before `a`
if (b.end.line < a.start.line || (b.end.line === a.start.line && b.end.character < a.start.character)) {
return false;
}

// These ranges must intersect
return true;
}

/**
* Test if `position` is in `range`. If the position is at the edges, will return true.
* Adapted from core vscode
Expand Down