Change:
! Open Put the cursor on a tslint warning Get a lightbulb with quick fix suggestions, but it blinks Seems to be related to cursor blink I think this is a regression from 1.34 but can't be sure because it doesn't happen totally consistently.
Repos for me in that specific file around line 90. Weird Looks like something is causing loops of refactoring requests
Looks like a real js/ts bug but not a regression. Too risky to fix this iteration as it involves scheduling and how we manage errors for TypeScript
The cause: Code requests diagnostics (it doesn't matter why, but it has to happen in a state where there is a pending request against the TSServer for the current file) our js/ts refactoring provider, we tell TS server to cancel its current work computing diagnostics (because we want to service the code actions request as soon as possible) we cancel the current request to the tsserver, trigger a new request, and then reschedules a new request with the current file in it refactor response is returned so we show the lightbulb then we get back part of the geterr response (but not the full response). This partial response updates diagnostics in the current file after a short delay (even if they have not changed) diagnostic change cause VS code to request code actions again while we still have pending diagnostics for the current file to step 1 I don't understand why this doesn't happen all the time

Discussion:
import * as vscode from 'vscode'; import { ResourceMap } from '../utils/resourceMap'; import { DiagnosticLanguage, allDiagnosticLanguages } from '../utils/languageDescription'; <ins> import * as arrays from '../utils/arrays'; function diagnosticsEquals(a: vscode.Diagnostic, b: vscode.Diagnostic): boolean { if (a === b) { return true; } return a.code === b.code && a.message === b.message && a.severity === b.severity && a.source === b.source && a.range.isEqual(b.range) && arrays.equals(a.relatedInformation || arrays.empty, b.relatedInformation || arrays.empty, (a, b) => { return a.message === b.message && a.location.range.isEqual(b.location.range) && a.location.uri.fsPath === b.location.uri.fsPath; }) && arrays.equals(a.tags || arrays.empty, b.tags || arrays.empty); } </ins> export const enum DiagnosticKind { Syntax,

this.language = language; } <del> if (diagnostics.length === 0) { const existing = this._diagnostics.get(kind); if (!existing || existing && existing.length === 0) { // No need to update return false; } </del> <ins> const existing = this._diagnostics.get(kind); if (arrays.equals(existing || arrays.empty, diagnostics, diagnosticsEquals)) { // No need to update return false; </ins> } this._diagnostics.set(kind, diagnostics);

*  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> export function equals<T>(one: ReadonlyArray<T>, other: ReadonlyArray<T>, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean { if (one.length !== other.length) { return false; } for (let i = 0, len = one.length; i < len; i++) { if (!itemEquals(one[i], other[i])) { return false; } } </del> <ins> export const empty = Object.freeze([]); </ins> <del> return true; </del> <ins> export function equals<T>( a: ReadonlyArray<T>, b: ReadonlyArray<T>, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b ): boolean { if (a === b) { return true; } if (a.length !== b.length) { return false; } return a.every((x, i) => itemEquals(x, b[i])); </ins> } export function flatten<T>(arr: ReadonlyArray<T>[]): T[] { <del> return ([] as T[]).concat.apply([], arr); </del> <ins> return Array.prototype.concat.apply([], arr); </ins> }  No newline at end of file