mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-08-16 22:50:22 +03:00
Be more aggressive in determining suggested indent positions…
…at ends of transactions — instead of falling back to a transaction-wide auto-indent quite so easily.
This commit is contained in:
parent
2827e6a4c4
commit
afe6e1e7bf
@ -4120,43 +4120,93 @@ describe('WASMTreeSitterLanguageMode', () => {
|
||||
await grammar.setQueryForTest('indentsQuery', `
|
||||
["{"] @indent
|
||||
["}"] @dedent
|
||||
`);
|
||||
`);
|
||||
|
||||
let emptyClassText = dedent`
|
||||
class Example {
|
||||
let emptyClassText = dedent`
|
||||
class Example {
|
||||
|
||||
}
|
||||
`;
|
||||
}
|
||||
`;
|
||||
|
||||
buffer.setText(emptyClassText);
|
||||
buffer.setText(emptyClassText);
|
||||
|
||||
const languageMode = new WASMTreeSitterLanguageMode({ grammar, buffer });
|
||||
buffer.setLanguageMode(languageMode);
|
||||
await languageMode.ready;
|
||||
const languageMode = new WASMTreeSitterLanguageMode({ grammar, buffer });
|
||||
buffer.setLanguageMode(languageMode);
|
||||
await languageMode.ready;
|
||||
|
||||
editor.setCursorBufferPosition([1, 0]);
|
||||
editor.indent();
|
||||
await languageMode.atTransactionEnd();
|
||||
editor.insertText('// this is a comment', { autoIndent: true });
|
||||
await languageMode.atTransactionEnd();
|
||||
expect(editor.lineTextForBufferRow(1)).toEqual(' // this is a comment');
|
||||
editor.setCursorBufferPosition([1, 0]);
|
||||
editor.indent();
|
||||
await languageMode.atTransactionEnd();
|
||||
editor.insertText('// this is a comment', { autoIndent: true });
|
||||
await languageMode.atTransactionEnd();
|
||||
expect(editor.lineTextForBufferRow(1)).toEqual(' // this is a comment');
|
||||
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(2)).toEqual(' ');
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(2)).toEqual(' ');
|
||||
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(3)).toEqual(' ');
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(3)).toEqual(' ');
|
||||
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(4)).toEqual(' ');
|
||||
editor.insertNewline();
|
||||
await languageMode.atTransactionEnd();
|
||||
await wait(0);
|
||||
expect(editor.lineTextForBufferRow(4)).toEqual(' ');
|
||||
});
|
||||
|
||||
it(`can indent properly in a multi-cursor environment without auto-indenting large ranges of the buffer`, async () => {
|
||||
jasmine.useRealClock();
|
||||
const grammar = new WASMTreeSitterGrammar(atom.grammars, jsGrammarPath, jsConfig);
|
||||
|
||||
expect(editor.getUndoGroupingInterval()).toBe(300);
|
||||
|
||||
await grammar.setQueryForTest('indentsQuery', `
|
||||
["{"] @indent
|
||||
["}"] @dedent
|
||||
`);
|
||||
|
||||
const languageMode = new WASMTreeSitterLanguageMode({ grammar, buffer });
|
||||
buffer.setLanguageMode(languageMode);
|
||||
await languageMode.ready;
|
||||
|
||||
// No spaces after the `{`s in these examples so that we can more easily
|
||||
// compare expected output to actual output.
|
||||
buffer.setText(dedent`
|
||||
function test () {return }
|
||||
|
||||
function test () {return }
|
||||
|
||||
function test () {return }
|
||||
`);
|
||||
|
||||
editor.setCursorBufferPosition([0, 18])
|
||||
editor.addCursorAtBufferPosition([2, 18])
|
||||
editor.addCursorAtBufferPosition([4, 18])
|
||||
|
||||
editor.insertNewline({
|
||||
autoIndent: true,
|
||||
autoIndentNewline: true,
|
||||
autoDecreaseIndent: true
|
||||
})
|
||||
|
||||
await wait(0);
|
||||
|
||||
expect(buffer.getText()).toBe(dedent`
|
||||
function test () {
|
||||
return }
|
||||
|
||||
function test () {
|
||||
return }
|
||||
|
||||
function test () {
|
||||
return }
|
||||
`)
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1270,6 +1270,7 @@ class WASMTreeSitterLanguageMode {
|
||||
if (!controllingLayer.treeIsDirty || options.forceTreeParse || !this.useAsyncParsing || !this.useAsyncIndent) {
|
||||
indentTree = controllingLayer.getOrParseTree();
|
||||
} else {
|
||||
let lineForRow = this.buffer.lineForRow(row)
|
||||
// We can't answer this yet because we don't yet have a new syntax
|
||||
// tree. Return a promise that will fulfill once we can determine the
|
||||
// right indent level.
|
||||
@ -1278,23 +1279,31 @@ class WASMTreeSitterLanguageMode {
|
||||
// preliminary indent level and then follow up later with a more
|
||||
// accurate one. It's a bit disorienting that the editor falls back to
|
||||
// an indent level of `0` when a newline is inserted.
|
||||
return this.atTransactionEnd().then(({ changeCount }) => {
|
||||
if (changeCount > 1) {
|
||||
// There were multiple changes in this transaction, so it's not
|
||||
// safe to assume that the original row still needs its indentation
|
||||
// adjusted. The row could've been shifted up or down by other
|
||||
// edits, or it could've been deleted entirely.
|
||||
return this.atTransactionEnd().then(() => {
|
||||
if (lineForRow !== this.buffer.lineForRow(row)) {
|
||||
// We're now revisiting this indentation question at the end of the
|
||||
// transaction. Other changes may have taken place since we were
|
||||
// first asked what the indent level should be for this line. So
|
||||
// how do we know if the question is still relevant? After all, the
|
||||
// text that was on this row earlier might be on some other row
|
||||
// now.
|
||||
//
|
||||
// Instead, we return `undefined` here, and the `TextEditor` will
|
||||
// understand that its only recourse is to auto-indent the whole
|
||||
// extent of the transaction instead.
|
||||
// So we compare the text that was on the row when we were first
|
||||
// called… to the text that is on the row now that the transaction
|
||||
// is over. If they're the same, that's a _strong_ indicator that
|
||||
// the result we return will still be relevant.
|
||||
//
|
||||
// If not, as is the case in this code path, we return `undefined`,
|
||||
// signalling to the `TextEditor` that its only recourse is to
|
||||
// auto-indent the whole extent of the transaction instead.
|
||||
return undefined;
|
||||
}
|
||||
// Otherwise, it's safe to auto-indent this line alone, because it
|
||||
// was the only change in this transaction. But we've retained the
|
||||
// original values for `comparisonRow` and `comparisonRowIndent`
|
||||
// because that's the proper basis from which to determine the given
|
||||
// row's indent level.
|
||||
// If we get this far, it's safe to auto-indent this line. Either it
|
||||
// was the only change in its transaction or the other changes
|
||||
// happened on different lines. But we've retained the original
|
||||
// values for `comparisonRow` and `comparisonRowIndent` because
|
||||
// that's the proper basis from which to determine the given row's
|
||||
// indent level.
|
||||
let result = this.suggestedIndentForBufferRow(row, tabLength, {
|
||||
...rawOptions,
|
||||
comparisonRow: comparisonRow,
|
||||
@ -1379,6 +1388,18 @@ class WASMTreeSitterLanguageMode {
|
||||
continue;
|
||||
}
|
||||
indentDelta--;
|
||||
if (indentDelta < 0) {
|
||||
// In the _indent_ phase, the delta won't ever go lower than `0`.
|
||||
// This is because we assume that the previous line is correctly
|
||||
// indented! The only function that `dedent` has for us is canceling
|
||||
// out any `indent` and preventing false positives.
|
||||
//
|
||||
// So no matter how many `dedent` tokens we see on a particular line…
|
||||
// if the _last_ token we see is an `indent` token, then it hints
|
||||
// that the next line should be indented by one level.
|
||||
indentDelta = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user