Path: blob/main/src/vs/editor/contrib/inlineCompletions/test/browser/inlineCompletions.test.ts
4798 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { timeout } from '../../../../../base/common/async.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { Range } from '../../../../common/core/range.js';9import { InlineCompletionsModel } from '../../browser/model/inlineCompletionsModel.js';10import { IWithAsyncTestCodeEditorAndInlineCompletionsModel, MockInlineCompletionsProvider, withAsyncTestCodeEditorAndInlineCompletionsModel } from './utils.js';11import { ITestCodeEditor } from '../../../../test/browser/testCodeEditor.js';12import { Selection } from '../../../../common/core/selection.js';1314suite('Inline Completions', () => {15ensureNoDisposablesAreLeakedInTestSuite();1617test('Does not trigger automatically if disabled', async function () {18const provider = new MockInlineCompletionsProvider();19await withAsyncTestCodeEditorAndInlineCompletionsModel('',20{ fakeClock: true, provider, inlineSuggest: { enabled: false } },21async ({ editor, editorViewModel, model, context }) => {22context.keyboardType('foo');23await timeout(1000);2425// Provider is not called, no ghost text is shown.26assert.deepStrictEqual(provider.getAndClearCallHistory(), []);27assert.deepStrictEqual(context.getAndClearViewStates(), ['']);28}29);30});3132test('Ghost text is shown after trigger', async function () {33const provider = new MockInlineCompletionsProvider();34await withAsyncTestCodeEditorAndInlineCompletionsModel('',35{ fakeClock: true, provider },36async ({ editor, editorViewModel, model, context }) => {37context.keyboardType('foo');38provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });39model.triggerExplicitly();40await timeout(1000);4142assert.deepStrictEqual(provider.getAndClearCallHistory(), [43{ position: '(1,4)', text: 'foo', triggerKind: 1, }44]);45assert.deepStrictEqual(context.getAndClearViewStates(), ['', 'foo[bar]']);46}47);48});4950test('Ghost text is shown automatically when configured', async function () {51const provider = new MockInlineCompletionsProvider();52await withAsyncTestCodeEditorAndInlineCompletionsModel('',53{ fakeClock: true, provider, inlineSuggest: { enabled: true } },54async ({ editor, editorViewModel, model, context }) => {55context.keyboardType('foo');5657provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });58await timeout(1000);5960assert.deepStrictEqual(provider.getAndClearCallHistory(), [61{ position: '(1,4)', text: 'foo', triggerKind: 0, }62]);63assert.deepStrictEqual(context.getAndClearViewStates(), ['', 'foo[bar]']);64}65);66});6768test('Ghost text is updated automatically', async function () {69const provider = new MockInlineCompletionsProvider();70await withAsyncTestCodeEditorAndInlineCompletionsModel('',71{ fakeClock: true, provider },72async ({ editor, editorViewModel, model, context }) => {73provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });74context.keyboardType('foo');75model.triggerExplicitly();76await timeout(1000);7778provider.setReturnValue({ insertText: 'foobizz', range: new Range(1, 1, 1, 6) });79context.keyboardType('b');80context.keyboardType('i');81await timeout(1000);8283assert.deepStrictEqual(provider.getAndClearCallHistory(), [84{ position: '(1,4)', text: 'foo', triggerKind: 1, },85{ position: '(1,6)', text: 'foobi', triggerKind: 0, }86]);87assert.deepStrictEqual(88context.getAndClearViewStates(),89['', 'foo[bar]', 'foob[ar]', 'foobi', 'foobi[zz]']90);91}92);93});9495test('Unindent whitespace', async function () {96const provider = new MockInlineCompletionsProvider();97await withAsyncTestCodeEditorAndInlineCompletionsModel('',98{ fakeClock: true, provider },99async ({ editor, editorViewModel, model, context }) => {100context.keyboardType(' ');101provider.setReturnValue({ insertText: 'foo', range: new Range(1, 2, 1, 3) });102model.triggerExplicitly();103await timeout(1000);104105assert.deepStrictEqual(context.getAndClearViewStates(), ['', ' [foo]']);106107model.accept(editor);108109assert.deepStrictEqual(provider.getAndClearCallHistory(), [110{ position: '(1,3)', text: ' ', triggerKind: 1, },111]);112113assert.deepStrictEqual(context.getAndClearViewStates(), [' foo']);114}115);116});117118test('Unindent tab', async function () {119const provider = new MockInlineCompletionsProvider();120await withAsyncTestCodeEditorAndInlineCompletionsModel('',121{ fakeClock: true, provider },122async ({ editor, editorViewModel, model, context }) => {123context.keyboardType('\t\t');124provider.setReturnValue({ insertText: 'foo', range: new Range(1, 2, 1, 3) });125model.triggerExplicitly();126await timeout(1000);127128assert.deepStrictEqual(context.getAndClearViewStates(), ['', '\t\t[foo]']);129130model.accept(editor);131132assert.deepStrictEqual(provider.getAndClearCallHistory(), [133{ position: '(1,3)', text: '\t\t', triggerKind: 1, },134]);135136assert.deepStrictEqual(context.getAndClearViewStates(), ['\tfoo']);137}138);139});140141test('No unindent after indentation', async function () {142const provider = new MockInlineCompletionsProvider();143await withAsyncTestCodeEditorAndInlineCompletionsModel('',144{ fakeClock: true, provider },145async ({ editor, editorViewModel, model, context }) => {146context.keyboardType('buzz ');147provider.setReturnValue({ insertText: 'foo', range: new Range(1, 6, 1, 7) });148model.triggerExplicitly();149await timeout(1000);150151assert.deepStrictEqual(context.getAndClearViewStates(), ['']);152153model.accept(editor);154155assert.deepStrictEqual(provider.getAndClearCallHistory(), [156{ position: '(1,7)', text: 'buzz ', triggerKind: 1, },157]);158159assert.deepStrictEqual(context.getAndClearViewStates(), []);160}161);162});163164test('Next/previous', async function () {165const provider = new MockInlineCompletionsProvider();166await withAsyncTestCodeEditorAndInlineCompletionsModel('',167{ fakeClock: true, provider },168async ({ editor, editorViewModel, model, context }) => {169context.keyboardType('foo');170provider.setReturnValue({ insertText: 'foobar1', range: new Range(1, 1, 1, 4) });171model.trigger();172await timeout(1000);173174assert.deepStrictEqual(175context.getAndClearViewStates(),176['', 'foo[bar1]']177);178179provider.setReturnValues([180{ insertText: 'foobar1', range: new Range(1, 1, 1, 4) },181{ insertText: 'foobizz2', range: new Range(1, 1, 1, 4) },182{ insertText: 'foobuzz3', range: new Range(1, 1, 1, 4) }183]);184185model.next();186await timeout(1000);187assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[bizz2]']);188189model.next();190await timeout(1000);191assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[buzz3]']);192193model.next();194await timeout(1000);195assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[bar1]']);196197model.previous();198await timeout(1000);199assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[buzz3]']);200201model.previous();202await timeout(1000);203assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[bizz2]']);204205model.previous();206await timeout(1000);207assert.deepStrictEqual(context.getAndClearViewStates(), ['foo[bar1]']);208209assert.deepStrictEqual(provider.getAndClearCallHistory(), [210{ position: '(1,4)', text: 'foo', triggerKind: 0, },211{ position: '(1,4)', text: 'foo', triggerKind: 1, },212]);213}214);215});216217test('Calling the provider is debounced', async function () {218const provider = new MockInlineCompletionsProvider();219await withAsyncTestCodeEditorAndInlineCompletionsModel('',220{ fakeClock: true, provider },221async ({ editor, editorViewModel, model, context }) => {222model.trigger();223224context.keyboardType('f');225await timeout(40);226context.keyboardType('o');227await timeout(40);228context.keyboardType('o');229await timeout(40);230231// The provider is not called232assert.deepStrictEqual(provider.getAndClearCallHistory(), []);233234await timeout(400);235assert.deepStrictEqual(provider.getAndClearCallHistory(), [236{ position: '(1,4)', text: 'foo', triggerKind: 0, }237]);238239provider.assertNotCalledTwiceWithin50ms();240}241);242});243244test('Backspace is debounced', async function () {245const provider = new MockInlineCompletionsProvider();246await withAsyncTestCodeEditorAndInlineCompletionsModel('',247{ fakeClock: true, provider, inlineSuggest: { enabled: true } },248async ({ editor, editorViewModel, model, context }) => {249context.keyboardType('foo');250251provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });252await timeout(1000);253254for (let j = 0; j < 2; j++) {255for (let i = 0; i < 3; i++) {256context.leftDelete();257await timeout(5);258}259260context.keyboardType('bar');261}262263await timeout(400);264265provider.assertNotCalledTwiceWithin50ms();266}267);268});269270271suite('Forward Stability', () => {272test('Typing agrees', async function () {273// The user types the text as suggested and the provider is forward-stable274const provider = new MockInlineCompletionsProvider();275await withAsyncTestCodeEditorAndInlineCompletionsModel('',276{ fakeClock: true, provider },277async ({ editor, editorViewModel, model, context }) => {278provider.setReturnValue({ insertText: 'foobar', });279context.keyboardType('foo');280model.trigger();281await timeout(1000);282assert.deepStrictEqual(provider.getAndClearCallHistory(), [283{ position: '(1,4)', text: 'foo', triggerKind: 0, }284]);285assert.deepStrictEqual(context.getAndClearViewStates(), ['', 'foo[bar]']);286287context.keyboardType('b');288assert.deepStrictEqual(context.getAndClearViewStates(), (['foob[ar]']));289await timeout(1000);290assert.deepStrictEqual(provider.getAndClearCallHistory(), [291{ position: '(1,5)', text: 'foob', triggerKind: 0, }292]);293assert.deepStrictEqual(context.getAndClearViewStates(), []);294295context.keyboardType('a');296assert.deepStrictEqual(context.getAndClearViewStates(), (['fooba[r]']));297await timeout(1000);298assert.deepStrictEqual(provider.getAndClearCallHistory(), [299{ position: '(1,6)', text: 'fooba', triggerKind: 0, }300]);301assert.deepStrictEqual(context.getAndClearViewStates(), []);302}303);304});305306async function setupScenario({ editor, editorViewModel, model, context, store }: IWithAsyncTestCodeEditorAndInlineCompletionsModel, provider: MockInlineCompletionsProvider): Promise<void> {307assert.deepStrictEqual(context.getAndClearViewStates(), ['']);308provider.setReturnValue({ insertText: 'foo bar' });309context.keyboardType('f');310model.triggerExplicitly();311await timeout(10000);312assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(1,2)', triggerKind: 1, text: 'f' }]));313assert.deepStrictEqual(context.getAndClearViewStates(), (['f[oo bar]']));314315provider.setReturnValue({ insertText: 'foo baz' });316await timeout(10000);317}318319test('Support forward instability', async function () {320// The user types the text as suggested and the provider reports a different suggestion.321const provider = new MockInlineCompletionsProvider();322await withAsyncTestCodeEditorAndInlineCompletionsModel('',323{ fakeClock: true, provider },324async (ctx) => {325await setupScenario(ctx, provider);326327ctx.context.keyboardType('o');328assert.deepStrictEqual(ctx.context.getAndClearViewStates(), ['fo[o bar]']);329await timeout(10000);330331assert.deepStrictEqual(provider.getAndClearCallHistory(), [332{ position: '(1,3)', text: 'fo', triggerKind: 0, }333]);334assert.deepStrictEqual(ctx.context.getAndClearViewStates(), ['fo[o baz]']);335}336);337});338339340test('when accepting word by word', async function () {341// The user types the text as suggested and the provider reports a different suggestion.342// Even when triggering explicitly, we want to keep the suggestion.343344const provider = new MockInlineCompletionsProvider();345await withAsyncTestCodeEditorAndInlineCompletionsModel('',346{ fakeClock: true, provider },347async (ctx) => {348await setupScenario(ctx, provider);349350await ctx.model.acceptNextWord();351assert.deepStrictEqual(ctx.context.getAndClearViewStates(), (['foo[ bar]']));352353await timeout(10000);354assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(1,4)', triggerKind: 0, text: 'foo' }]));355assert.deepStrictEqual(ctx.context.getAndClearViewStates(), ([]));356357await ctx.model.triggerExplicitly(); // reset to provider truth358await timeout(10000);359assert.deepStrictEqual(ctx.context.getAndClearViewStates(), ([]));360}361);362});363364test('when accepting undo', async function () {365// The user types the text as suggested and the provider reports a different suggestion.366367const provider = new MockInlineCompletionsProvider();368await withAsyncTestCodeEditorAndInlineCompletionsModel('',369{ fakeClock: true, provider },370async (ctx) => {371await setupScenario(ctx, provider);372373await ctx.model.acceptNextWord();374assert.deepStrictEqual(ctx.context.getAndClearViewStates(), (['foo[ bar]']));375376await timeout(10000);377assert.deepStrictEqual(ctx.context.getAndClearViewStates(), ([]));378assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(1,4)', triggerKind: 0, text: 'foo' }]));379380await ctx.editor.getModel().undo();381await timeout(10000);382assert.deepStrictEqual(ctx.context.getAndClearViewStates(), (['f[oo bar]']));383assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(1,2)', triggerKind: 0, text: 'f' }]));384385await ctx.editor.getModel().redo();386await timeout(10000);387assert.deepStrictEqual(ctx.context.getAndClearViewStates(), (['foo[ bar]']));388assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(1,4)', triggerKind: 0, text: 'foo' }]));389}390);391});392393test('Support backward instability', async function () {394// The user deletes text and the suggestion changes395const provider = new MockInlineCompletionsProvider();396await withAsyncTestCodeEditorAndInlineCompletionsModel('',397{ fakeClock: true, provider },398async ({ editor, editorViewModel, model, context }) => {399context.keyboardType('fooba');400401provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 6) });402403model.triggerExplicitly();404await timeout(1000);405assert.deepStrictEqual(provider.getAndClearCallHistory(), [406{ position: '(1,6)', text: 'fooba', triggerKind: 1, }407]);408assert.deepStrictEqual(context.getAndClearViewStates(), ['', 'fooba[r]']);409410provider.setReturnValue({ insertText: 'foobaz', range: new Range(1, 1, 1, 5) });411context.leftDelete();412await timeout(1000);413assert.deepStrictEqual(provider.getAndClearCallHistory(), [414{ position: '(1,5)', text: 'foob', triggerKind: 0, }415]);416assert.deepStrictEqual(context.getAndClearViewStates(), [417'foob[ar]',418'foob[az]'419]);420}421);422});423424test('Push item to preserve to front', async function () {425const provider = new MockInlineCompletionsProvider(true);426await withAsyncTestCodeEditorAndInlineCompletionsModel('',427{ fakeClock: true, provider },428async ({ editor, editorViewModel, model, context }) => {429provider.setReturnValue({ insertText: 'foobar', range: new Range(1, 1, 1, 4) });430context.keyboardType('foo');431await timeout(1000);432433assert.deepStrictEqual(provider.getAndClearCallHistory(), ([434{435position: '(1,4)',436triggerKind: 0,437text: 'foo'438}439]));440assert.deepStrictEqual(context.getAndClearViewStates(),441([442'',443'foo[bar]'444])445);446447provider.setReturnValues([{ insertText: 'foobar1', range: new Range(1, 1, 1, 4) }, { insertText: 'foobar', range: new Range(1, 1, 1, 4) }]);448449await model.triggerExplicitly();450await timeout(1000);451452assert.deepStrictEqual(provider.getAndClearCallHistory(), ([453{454position: '(1,4)',455triggerKind: 1,456text: 'foo'457}458]));459assert.deepStrictEqual(context.getAndClearViewStates(),460([])461);462}463);464});465});466467test('No race conditions', async function () {468const provider = new MockInlineCompletionsProvider();469await withAsyncTestCodeEditorAndInlineCompletionsModel('',470{ fakeClock: true, provider, },471async ({ editor, editorViewModel, model, context }) => {472context.keyboardType('h');473provider.setReturnValue({ insertText: 'helloworld', range: new Range(1, 1, 1, 2) }, 1000);474475model.triggerExplicitly();476477await timeout(1030);478context.keyboardType('ello');479provider.setReturnValue({ insertText: 'helloworld', range: new Range(1, 1, 1, 6) }, 1000);480481// after 20ms: Inline completion provider answers back482// after 50ms: Debounce is triggered483await timeout(2000);484485assert.deepStrictEqual(context.getAndClearViewStates(), [486'',487'hello[world]',488]);489});490});491492test('Do not reuse cache from previous session (#132516)', async function () {493const provider = new MockInlineCompletionsProvider();494await withAsyncTestCodeEditorAndInlineCompletionsModel('',495{ fakeClock: true, provider, inlineSuggest: { enabled: true } },496async ({ editor, editorViewModel, model, context }) => {497context.keyboardType('hello\n');498context.cursorLeft();499context.keyboardType('x');500context.leftDelete();501provider.setReturnValue({ insertText: 'helloworld', range: new Range(1, 1, 1, 6) }, 1000);502await timeout(2000);503504assert.deepStrictEqual(provider.getAndClearCallHistory(), [505{506position: '(1,6)',507text: 'hello\n',508triggerKind: 0,509}510]);511512provider.setReturnValue({ insertText: 'helloworld', range: new Range(2, 1, 2, 6) }, 1000);513514context.cursorDown();515context.keyboardType('hello');516await timeout(40);517518assert.deepStrictEqual(provider.getAndClearCallHistory(), []);519520// Update ghost text521context.keyboardType('w');522context.leftDelete();523524await timeout(2000);525526assert.deepStrictEqual(provider.getAndClearCallHistory(), [527{ position: '(2,6)', triggerKind: 0, text: 'hello\nhello' },528]);529530assert.deepStrictEqual(context.getAndClearViewStates(), [531'',532'hello[world]\n',533'hello\n',534'hello\nhello[world]',535]);536});537});538539test('Additional Text Edits', async function () {540const provider = new MockInlineCompletionsProvider();541await withAsyncTestCodeEditorAndInlineCompletionsModel('',542{ fakeClock: true, provider },543async ({ editor, editorViewModel, model, context }) => {544context.keyboardType('buzz\nbaz');545provider.setReturnValue({546insertText: 'bazz',547range: new Range(2, 1, 2, 4),548additionalTextEdits: [{549range: new Range(1, 1, 1, 5),550text: 'bla'551}],552});553model.triggerExplicitly();554await timeout(1000);555556model.accept(editor);557558assert.deepStrictEqual(provider.getAndClearCallHistory(), ([{ position: '(2,4)', triggerKind: 1, text: 'buzz\nbaz' }]));559560assert.deepStrictEqual(context.getAndClearViewStates(), [561'',562'buzz\nbaz[z]',563'bla\nbazz',564]);565}566);567});568});569570suite('Multi Cursor Support', () => {571ensureNoDisposablesAreLeakedInTestSuite();572573test('Basic', async function () {574const provider = new MockInlineCompletionsProvider();575await withAsyncTestCodeEditorAndInlineCompletionsModel('',576{ fakeClock: true, provider },577async ({ editor, editorViewModel, model, context }) => {578context.keyboardType('console\nconsole\n');579editor.setSelections([580new Selection(1, 1000, 1, 1000),581new Selection(2, 1000, 2, 1000),582]);583provider.setReturnValue({584insertText: 'console.log("hello");',585range: new Range(1, 1, 1, 1000),586});587model.triggerExplicitly();588await timeout(1000);589model.accept(editor);590assert.deepStrictEqual(591editor.getValue(),592[593`console.log("hello");`,594`console.log("hello");`,595``596].join('\n')597);598}599);600});601602test('Multi Part', async function () {603const provider = new MockInlineCompletionsProvider();604await withAsyncTestCodeEditorAndInlineCompletionsModel('',605{ fakeClock: true, provider },606async ({ editor, editorViewModel, model, context }) => {607context.keyboardType('console.log()\nconsole.log\n');608editor.setSelections([609new Selection(1, 12, 1, 12),610new Selection(2, 1000, 2, 1000),611]);612provider.setReturnValue({613insertText: 'console.log("hello");',614range: new Range(1, 1, 1, 1000),615});616model.triggerExplicitly();617await timeout(1000);618model.accept(editor);619assert.deepStrictEqual(620editor.getValue(),621[622`console.log("hello");`,623`console.log`,624``625].join('\n')626);627}628);629});630631test('Multi Part and Different Cursor Columns', async function () {632const provider = new MockInlineCompletionsProvider();633await withAsyncTestCodeEditorAndInlineCompletionsModel('',634{ fakeClock: true, provider },635async ({ editor, editorViewModel, model, context }) => {636context.keyboardType('console.log()\nconsole.warn\n');637editor.setSelections([638new Selection(1, 12, 1, 12),639new Selection(2, 14, 2, 14),640]);641provider.setReturnValue({642insertText: 'console.log("hello");',643range: new Range(1, 1, 1, 1000),644});645model.triggerExplicitly();646await timeout(1000);647model.accept(editor);648assert.deepStrictEqual(649editor.getValue(),650[651`console.log("hello");`,652`console.warn`,653``654].join('\n')655);656}657);658});659660async function acceptNextWord(model: InlineCompletionsModel, editor: ITestCodeEditor, timesToAccept: number = 1): Promise<void> {661for (let i = 0; i < timesToAccept; i++) {662model.triggerExplicitly();663await timeout(1000);664await model.acceptNextWord();665}666}667668test('Basic Partial Completion', async function () {669const provider = new MockInlineCompletionsProvider();670await withAsyncTestCodeEditorAndInlineCompletionsModel('',671{ fakeClock: true, provider },672async ({ editor, editorViewModel, model, context }) => {673context.keyboardType('let\nlet\n');674editor.setSelections([675new Selection(1, 1000, 1, 1000),676new Selection(2, 1000, 2, 1000),677]);678679provider.setReturnValue({680insertText: `let a = 'some word'; `,681range: new Range(1, 1, 1, 1000),682});683684await acceptNextWord(model, editor, 2);685686assert.deepStrictEqual(687editor.getValue(),688[689`let a`,690`let a`,691``692].join('\n')693);694}695);696});697698test('Partial Multi-Part Completion', async function () {699const provider = new MockInlineCompletionsProvider();700await withAsyncTestCodeEditorAndInlineCompletionsModel('',701{ fakeClock: true, provider },702async ({ editor, editorViewModel, model, context }) => {703context.keyboardType('for ()\nfor \n');704editor.setSelections([705new Selection(1, 5, 1, 5),706new Selection(2, 1000, 2, 1000),707]);708709provider.setReturnValue({710insertText: `for (let i = 0; i < 10; i++) {`,711range: new Range(1, 1, 1, 1000),712});713714model.triggerExplicitly();715await timeout(1000);716717await acceptNextWord(model, editor, 3);718719assert.deepStrictEqual(720editor.getValue(),721[722`for (let i)`,723`for `,724``725].join('\n')726);727}728);729});730731test('Partial Mutli-Part and Different Cursor Columns Completion', async function () {732const provider = new MockInlineCompletionsProvider();733await withAsyncTestCodeEditorAndInlineCompletionsModel('',734{ fakeClock: true, provider },735async ({ editor, editorViewModel, model, context }) => {736context.keyboardType(`console.log()\nconsole.warnnnn\n`);737editor.setSelections([738new Selection(1, 12, 1, 12),739new Selection(2, 16, 2, 16),740]);741742provider.setReturnValue({743insertText: `console.log("hello" + " " + "world");`,744range: new Range(1, 1, 1, 1000),745});746747model.triggerExplicitly();748await timeout(1000);749750await acceptNextWord(model, editor, 4);751752assert.deepStrictEqual(753editor.getValue(),754[755`console.log("hello" + )`,756`console.warnnnn`,757``758].join('\n')759);760}761);762});763});764765766