Skip to content

Commit

Permalink
renamed rangeForDefun2 -> rangeForDefun, tests cleanup, changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
brdloush committed Jul 17, 2021
1 parent 362407d commit 5e4f02b
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 121 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Changes to Calva.

## [Unreleased]
- Performance improvement [REPL is Slow and Performance Degrades as the Output Grows](https://github.com/BetterThanTomorrow/calva/issues/942)

## [2.0.204] - 2021-07-11
- [Put closing paren of rich comments on separate line](https://github.com/BetterThanTomorrow/calva/issues/1224)
Expand Down
2 changes: 1 addition & 1 deletion src/cursor-doc/paredit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function selectOpenList(doc: EditableDocument) {
*/
export function rangeForDefun(doc: EditableDocument, offset: number = doc.selection.active): [number, number] {
const cursor = doc.getTokenCursor(offset);
return cursor.rangeForDefun2(offset);
return cursor.rangeForDefun(offset);
}

export function forwardSexpRange(doc: EditableDocument, offset = Math.max(doc.selection.anchor, doc.selection.active), goPastWhitespace = false): [number, number] {
Expand Down
34 changes: 2 additions & 32 deletions src/cursor-doc/token-cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,39 +602,9 @@ export class LispTokenCursor extends TokenCursor {
}
}
return undefined; // 8.
}

/**
* Gets the range for the ”current” top level form, visiting forms from the cursor towards `offset`
* With `commentCreatesTopLevel` as true (default): If the current top level form is a `(comment ...)`, consider it creating a new top level and continue the search.
* @param offset The ”current” position
* @param depth Controls if the cursor should consider `comment` top level (if > 0, it will not)
* @param commentIsTopLevel? Controls
*/
rangeForDefun(offset: number, depth = 0, commentCreatesTopLevel = true): [number, number] {
const cursor = this.clone();

while (cursor.forwardSexp()) {
if (cursor.offsetEnd >= offset) {
if (depth < 1 && cursor.getPrevToken().raw === ')') {
const commentCursor = cursor.clone();
commentCursor.previous();
if (commentCursor.getFunctionName() === 'comment' && commentCreatesTopLevel) {
commentCursor.backwardList();
commentCursor.forwardWhitespace();
commentCursor.forwardSexp();
return commentCursor.rangeForDefun(offset, depth + 1);
}
}
const end = cursor.offsetStart;
cursor.backwardSexp();
return [cursor.offsetStart, end];
}
}
return [offset, offset]
}
}

rangeForDefun2(offset: number, commentCreatesTopLevel = true): [number, number] {
rangeForDefun(offset: number, commentCreatesTopLevel = true): [number, number] {
const cursor = this.doc.getTokenCursor(offset);
let lastCandidateRange: [number, number] = cursor.rangeForCurrentForm(offset);
while (cursor.forwardList() && cursor.upList()) {
Expand Down
2 changes: 1 addition & 1 deletion src/debugger/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function moveCursorPastStringInList(tokenCursor: LispTokenCursor, s: string): vo
function moveTokenCursorToBreakpoint(tokenCursor: LispTokenCursor, debugResponse: any): LispTokenCursor {

const errorMessage = "Error finding position of breakpoint";
const [_, defunEnd] = tokenCursor.rangeForDefun2(tokenCursor.offsetStart);
const [_, defunEnd] = tokenCursor.rangeForDefun(tokenCursor.offsetStart);
let inSyntaxQuote = false;

const coor = [...debugResponse.coor]; // Copy the array so we do not modify the one stored in state
Expand Down
111 changes: 31 additions & 80 deletions src/extension-test/unit/cursor-doc/token-cursor-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,145 +366,96 @@ describe('Token Cursor', () => {
it('Finds range when nested down a some forms', () => {
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa |(bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds range when in current form is top level', () => { // Bug, documenting how it behaves
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(ddd eee)');
const b = docFromTextNotation('aaa |(bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds range when in ”solid” top level form', () => {
const a = docFromTextNotation('a|aa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('|aaa| (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds range for a top level form inside a comment', () => {
const a = docFromTextNotation('aaa (comment (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa (comment |(ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)|) (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Can find the comment range for a top level form inside a comment', () => {
const a = docFromTextNotation('aaa (comment (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa |(comment (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft, 0, false)).toEqual(textAndSelection(b)[1]);
});
it('Finds empty range for empty comment form', () => { // Unimportant use case, just documenting how it behaves
const a = docFromTextNotation('aaa (comment | ) bbb');
const b = docFromTextNotation('aaa (comment | ) bbb');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds comment range when comments are nested', () => { // TODO: Consider changing this behavior
const a = docFromTextNotation('aaa (comment (comment [bbb ccc] | ddd))');
const b = docFromTextNotation('aaa (comment |(comment [bbb ccc] ddd)|)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds comment range when current form is top level comment form', () => {
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (comment eee)| fff');
const b = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(comment eee)| fff');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Includes reader tag', () => {
const a = docFromTextNotation('aaa (comment #r [bbb ccc|] ddd)');
const b = docFromTextNotation('aaa (comment |#r [bbb ccc]| ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds the preceding range when cursor is between two forms on the same line', () => {
const a = docFromTextNotation('aaa (comment [bbb ccc] | ddd)');
const b = docFromTextNotation('aaa (comment |[bbb ccc]| ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds the succeeding range when cursor is at the start of the line', () => {
const a = docFromTextNotation('aaa (comment [bbb ccc]• | ddd)');
const b = docFromTextNotation('aaa (comment [bbb ccc]• |ddd|)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
});
describe('Top Level Form 2', () => {
it('Finds range when nested down a some forms', () => {
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa |(bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds range when in current form is top level', () => {
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(ddd eee)');
const b = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(ddd eee)|');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds range when in ”solid” top level form', () => {
const a = docFromTextNotation('a|aa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('|aaa| (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds range for a top level form inside a comment', () => {
const a = docFromTextNotation('aaa (comment (comment [bbb cc|c] ddd))');
const b = docFromTextNotation('aaa (comment (comment |[bbb ccc]| ddd))');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds top level comment range if comment special treatment is disabled', () => {
const a = docFromTextNotation('aaa (comment (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa |(comment (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active, false)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active, false)).toEqual(textAndSelection(b)[1]);
});
it('Finds comment range for empty comment form', () => { // Unimportant use case, just documenting how it behaves
const a = docFromTextNotation('aaa (comment | ) bbb');
const b = docFromTextNotation('aaa (|comment| ) bbb');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Does not find comment range when comments are nested', () => {
const a = docFromTextNotation('aaa (comment (comment [bbb ccc] | ddd))');
const b = docFromTextNotation('aaa (comment (comment |[bbb ccc]| ddd))');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds comment range when current form is top level comment form', () => {
const a = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(comment eee)');
const b = docFromTextNotation('aaa (bbb (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) |(comment eee)|');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Includes reader tag', () => {
const a = docFromTextNotation('aaa (comment #r [bbb ccc|] ddd)');
const b = docFromTextNotation('aaa (comment |#r [bbb ccc]| ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds the preceding range when cursor is between to forms on the same line', () => {
const a = docFromTextNotation('aaa (comment [bbb ccc] | ddd)');
const b = docFromTextNotation('aaa (comment |[bbb ccc]| ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds the succeeding range when cursor is at the start of the line', () => {
const a = docFromTextNotation('aaa (comment [bbb ccc]• | ddd)');
const b = docFromTextNotation('aaa (comment [bbb ccc]• |ddd|)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Finds the preceding comment symbol range when cursor is between that and something else on the same line', () => {
// This is a bit funny, but is not an important use case
const a = docFromTextNotation('aaa (comment | [bbb ccc] ddd)');
const b = docFromTextNotation('aaa (|comment| [bbb ccc] ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(a.selection.active);
expect(cursor.rangeForDefun2(a.selection.active)).toEqual(textAndSelection(b)[1]);
expect(cursor.rangeForDefun(a.selection.active)).toEqual(textAndSelection(b)[1]);
});
it('Can find the comment range for a top level form inside a comment', () => {
const a = docFromTextNotation('aaa (comment (ccc •#foo•(#bar •#baz•[:a :b| :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar)) (ddd eee)');
const b = docFromTextNotation('aaa |(comment (ccc •#foo•(#bar •#baz•[:a :b :c]•x•#(a b c))•#baz•yyy• z z z •foo• • bar))| (ddd eee)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft, false)).toEqual(textAndSelection(b)[1]);
});
it('Finds closest form inside multiple nested comments', () => {
const a = docFromTextNotation('aaa (comment (comment [bbb ccc] | ddd))');
const b = docFromTextNotation('aaa (comment (comment |[bbb ccc]| ddd))');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
it('Finds the preceding range when cursor is between two forms on the same line', () => {
const a = docFromTextNotation('aaa (comment [bbb ccc] | ddd)');
const b = docFromTextNotation('aaa (comment |[bbb ccc]| ddd)');
const cursor: LispTokenCursor = a.getTokenCursor(0);
expect(cursor.rangeForDefun(a.selectionLeft)).toEqual(textAndSelection(b)[1]);
});
});

describe('Location State', () => {
it('Knows when inside string', () => {
const doc = docFromTextNotation('(str [] "", "foo" "f b b" " f b b " "\\"" \\")');
Expand Down
4 changes: 2 additions & 2 deletions src/highlight/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ function updateRainbowBrackets() {
const startOffset = doc.offsetAt(range.start),
endOffset = doc.offsetAt(range.end),
startCursor: LispTokenCursor = mirrorDoc.getTokenCursor(0),
startRange = startCursor.rangeForDefun2(startOffset, false),
startRange = startCursor.rangeForDefun(startOffset, false),
endCursor: LispTokenCursor = mirrorDoc.getTokenCursor(endOffset),
endRange = endCursor.rangeForDefun2(endOffset, false),
endRange = endCursor.rangeForDefun(endOffset, false),
rangeStart = startRange[0],
rangeEnd = endRange[1];
// Look for top level ignores, and adjust starting point if found
Expand Down
2 changes: 1 addition & 1 deletion src/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function selectionFromOffsetRange(doc: vscode.TextDocument, range: [number, numb
function getFormSelection(doc: vscode.TextDocument, pos: vscode.Position, topLevel): vscode.Selection {
const idx = doc.offsetAt(pos);
const cursor = docMirror.getDocument(doc).getTokenCursor(idx);
const range = topLevel ? cursor.rangeForDefun2(idx) : cursor.rangeForCurrentForm(idx);
const range = topLevel ? cursor.rangeForDefun(idx) : cursor.rangeForCurrentForm(idx);
if (range) {
return selectionFromOffsetRange(doc, range);
}
Expand Down
Loading

0 comments on commit 5e4f02b

Please sign in to comment.