diff --git a/extensions/terminal-suggest/src/shell/pwsh.ts b/extensions/terminal-suggest/src/shell/pwsh.ts index 8926f72e516..5896309978f 100644 --- a/extensions/terminal-suggest/src/shell/pwsh.ts +++ b/extensions/terminal-suggest/src/shell/pwsh.ts @@ -66,33 +66,38 @@ async function getAliases(options: ExecOptionsWithStringEncoding, existingComman console.error('Error parsing output:', e); return []; } - return (json as any[]).map(e => { - // Aliases sometimes use the same Name and DisplayName, show them as methods in this case. - const isAlias = e.Name !== e.DisplayName; - const detailParts: string[] = []; - if (e.Definition) { - detailParts.push(e.Definition); - } - if (e.ModuleName && e.Version) { - detailParts.push(`${e.ModuleName} v${e.Version}`); - } - let definitionCommand = undefined; - if (e.Definition) { - let definitionIndex = e.Definition.indexOf(' '); - if (definitionIndex === -1) { - definitionIndex = e.Definition.length; - definitionCommand = e.Definition.substring(0, definitionIndex); + if (!Array.isArray(json)) { + return []; + } + return (json as unknown[]) + .filter(isPwshGetCommandEntry) + .map(e => { + // Aliases sometimes use the same Name and DisplayName, show them as methods in this case. + const isAlias = e.Name !== e.DisplayName; + const detailParts: string[] = []; + if (e.Definition) { + detailParts.push(e.Definition); } - } - return { - label: e.Name, - detail: detailParts.join('\n\n'), - kind: (isAlias - ? vscode.TerminalCompletionItemKind.Alias - : vscode.TerminalCompletionItemKind.Method), - definitionCommand, - }; - }); + if (e.ModuleName && e.Version) { + detailParts.push(`${e.ModuleName} v${e.Version}`); + } + let definitionCommand = undefined; + if (e.Definition) { + let definitionIndex = e.Definition.indexOf(' '); + if (definitionIndex === -1) { + definitionIndex = e.Definition.length; + definitionCommand = e.Definition.substring(0, definitionIndex); + } + } + return { + label: e.Name, + detail: detailParts.join('\n\n'), + kind: (isAlias + ? vscode.TerminalCompletionItemKind.Alias + : vscode.TerminalCompletionItemKind.Method), + definitionCommand, + }; + }); } async function getCommands(options: ExecOptionsWithStringEncoding, existingCommands?: Set): Promise { @@ -100,15 +105,19 @@ async function getCommands(options: ExecOptionsWithStringEncoding, existingComma ...options, maxBuffer: 1024 * 1024 * 100 // This is a lot of content, increase buffer size }); - let json: any; + let json: unknown; try { json = JSON.parse(output); } catch (e) { console.error('Error parsing pwsh output:', e); return []; } + if (!Array.isArray(json)) { + return []; + } return ( - (json as any[]) + (json as unknown[]) + .filter(isPwshGetCommandEntry) .filter(e => e.CommandType !== PwshCommandType.Alias) .map(e => { const detailParts: string[] = []; @@ -126,3 +135,39 @@ async function getCommands(options: ExecOptionsWithStringEncoding, existingComma }) ); } + +interface IPwshGetCommandEntry { + Name: string; + CommandType: PwshCommandType; + DisplayName?: string | null; + Definition?: string | null; + ModuleName?: string | null; + Version?: string | null; +} + +function isPwshGetCommandEntry(entry: unknown): entry is IPwshGetCommandEntry { + return ( + isObject(entry) && + 'Name' in entry && typeof entry.Name === 'string' && + 'CommandType' in entry && typeof entry.CommandType === 'number' && + (!('DisplayName' in entry) || typeof entry.DisplayName === 'string' || entry.DisplayName === null) && + (!('Definition' in entry) || typeof entry.Definition === 'string' || entry.Definition === null) && + (!('ModuleName' in entry) || typeof entry.ModuleName === 'string' || entry.ModuleName === null) && + (!('Version' in entry) || typeof entry.Version === 'string' || entry.Version === null) + ); +} + +/** + * @returns whether the provided parameter is of type `object` but **not** + * `null`, an `array`, a `regexp`, nor a `date`. + */ +export function isObject(obj: unknown): obj is Object { + // The method can't do a type cast since there are type (like strings) which + // are subclasses of any put not positvely matched by the function. Hence type + // narrowing results in wrong results. + return typeof obj === 'object' + && obj !== null + && !Array.isArray(obj) + && !(obj instanceof RegExp) + && !(obj instanceof Date); +} diff --git a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts index a2e38224ecc..5eeb1fe62e4 100644 --- a/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution.ts @@ -91,8 +91,7 @@ registerTerminalAction({ } escapedData = escapedData.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + escapedData.slice(match.index + 4); } - // eslint-disable-next-line local/code-no-any-casts - const xterm = instance.xterm as any as IInternalXtermTerminal; + const xterm = instance.xterm as IInternalXtermTerminal; xterm._writeText(escapedData); } }); diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkManager.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkManager.ts index 32abf0e15ca..6081c7f1555 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkManager.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkManager.ts @@ -149,8 +149,10 @@ export class TerminalLinkManager extends DisposableStore { activeHoverDisposable = undefined; activeTooltipScheduler?.dispose(); activeTooltipScheduler = new RunOnceScheduler(() => { - // eslint-disable-next-line local/code-no-any-casts - const core = (this._xterm as any)._core as IXtermCore; + interface XtermWithCore extends Terminal { + _core: IXtermCore; + } + const core = (this._xterm as XtermWithCore)._core; const cellDimensions = { width: core._renderService.dimensions.css.cell.width, height: core._renderService.dimensions.css.cell.height @@ -348,8 +350,10 @@ export class TerminalLinkManager extends DisposableStore { return; } - // eslint-disable-next-line local/code-no-any-casts - const core = (this._xterm as any)._core as IXtermCore; + interface XtermWithCore extends Terminal { + _core: IXtermCore; + } + const core = (this._xterm as XtermWithCore)._core; const cellDimensions = { width: core._renderService.dimensions.css.cell.width, height: core._renderService.dimensions.css.cell.height diff --git a/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts b/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts index ad86b75ae4c..f884f7fcb19 100644 --- a/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts +++ b/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts @@ -406,8 +406,10 @@ export class TerminalStickyScrollOverlay extends Disposable { } hoverOverlay.title = hoverTitle; - // eslint-disable-next-line local/code-no-any-casts - const scrollBarWidth = (this._xterm.raw as any as { _core: IXtermCore })._core.viewport?.scrollBarWidth; + interface XtermWithCore extends XTermTerminal { + _core: IXtermCore; + } + const scrollBarWidth = (this._xterm.raw as XtermWithCore)._core.viewport?.scrollBarWidth; if (scrollBarWidth !== undefined) { this._element.style.right = `${scrollBarWidth}px`; } diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts index b9fb6c090b0..eee28abf407 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon.ts @@ -682,8 +682,10 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest } private _getTerminalDimensions(): { width: number; height: number } { - // eslint-disable-next-line local/code-no-any-casts - const cssCellDims = (this._terminal as any as { _core: IXtermCore })._core._renderService.dimensions.css.cell; + interface XtermWithCore extends Terminal { + _core: IXtermCore; + } + const cssCellDims = (this._terminal as XtermWithCore)._core._renderService.dimensions.css.cell; return { width: cssCellDims.width, height: cssCellDims.height, @@ -708,8 +710,10 @@ export class SuggestAddon extends Disposable implements ITerminalAddon, ISuggest return this._cachedFontInfo; } - // eslint-disable-next-line local/code-no-any-casts - const core = (this._terminal as any)._core as IXtermCore; + interface XtermWithCore extends Terminal { + _core: IXtermCore; + } + const core = (this._terminal as XtermWithCore)._core; const font = this._terminalConfigurationService.getFont(dom.getActiveWindow(), core); let lineHeight: number = font.lineHeight; const fontSize: number = font.fontSize; diff --git a/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts b/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts index 48768032a9e..d2b2f3b0b72 100644 --- a/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts @@ -50,8 +50,12 @@ const enum StatsConstants { */ const PREDICTION_OMIT_RE = /^(\x1b\[(\??25[hl]|\??[0-9;]+n))+/; -// eslint-disable-next-line local/code-no-any-casts -const core = (terminal: Terminal): IXtermCore => (terminal as any)._core; +const core = (terminal: Terminal): IXtermCore => { + interface XtermWithCore extends Terminal { + _core: IXtermCore; + } + return (terminal as XtermWithCore)._core; +}; const flushOutput = (terminal: Terminal) => { // TODO: Flushing output is not possible anymore without async }; diff --git a/src/vs/workbench/contrib/terminalContrib/zoom/browser/terminal.zoom.contribution.ts b/src/vs/workbench/contrib/terminalContrib/zoom/browser/terminal.zoom.contribution.ts index 1d7337dc44e..cf4d8e63508 100644 --- a/src/vs/workbench/contrib/terminalContrib/zoom/browser/terminal.zoom.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/zoom/browser/terminal.zoom.contribution.ts @@ -71,43 +71,46 @@ class TerminalMouseWheelZoomContribution extends Disposable implements ITerminal let gestureHasZoomModifiers = false; let gestureAccumulatedDelta = 0; - raw.attachCustomWheelEventHandler((e: WheelEvent) => { - // eslint-disable-next-line local/code-no-any-casts - const browserEvent = e as any as IMouseWheelEvent; - if (classifier.isPhysicalMouseWheel()) { - if (this._hasMouseWheelZoomModifiers(browserEvent)) { - const delta = browserEvent.deltaY > 0 ? -1 : 1; - const newFontSize = this._clampFontSize(this._getConfigFontSize() + delta); - this._configurationService.updateValue(TerminalSettingId.FontSize, newFontSize); - // EditorZoom.setZoomLevel(zoomLevel + delta); - browserEvent.preventDefault(); - browserEvent.stopPropagation(); - return false; - } - } else { - // we consider mousewheel events that occur within 50ms of each other to be part of the same gesture - // we don't want to consider mouse wheel events where ctrl/cmd is pressed during the inertia phase - // we also want to accumulate deltaY values from the same gesture and use that to set the zoom level - if (Date.now() - prevMouseWheelTime > 50) { - // reset if more than 50ms have passed - gestureStartFontSize = this._getConfigFontSize(); - gestureHasZoomModifiers = this._hasMouseWheelZoomModifiers(browserEvent); - gestureAccumulatedDelta = 0; - } + raw.attachCustomWheelEventHandler((browserEvent: WheelEvent) => { + function isWheelEvent(e: MouseEvent): e is IMouseWheelEvent { + return 'wheelDelta' in e && 'wheelDeltaX' in e && 'wheelDeltaY' in e; + } + if (isWheelEvent(browserEvent)) { + if (classifier.isPhysicalMouseWheel()) { + if (this._hasMouseWheelZoomModifiers(browserEvent)) { + const delta = browserEvent.deltaY > 0 ? -1 : 1; + const newFontSize = this._clampFontSize(this._getConfigFontSize() + delta); + this._configurationService.updateValue(TerminalSettingId.FontSize, newFontSize); + // EditorZoom.setZoomLevel(zoomLevel + delta); + browserEvent.preventDefault(); + browserEvent.stopPropagation(); + return false; + } + } else { + // we consider mousewheel events that occur within 50ms of each other to be part of the same gesture + // we don't want to consider mouse wheel events where ctrl/cmd is pressed during the inertia phase + // we also want to accumulate deltaY values from the same gesture and use that to set the zoom level + if (Date.now() - prevMouseWheelTime > 50) { + // reset if more than 50ms have passed + gestureStartFontSize = this._getConfigFontSize(); + gestureHasZoomModifiers = this._hasMouseWheelZoomModifiers(browserEvent); + gestureAccumulatedDelta = 0; + } - prevMouseWheelTime = Date.now(); - gestureAccumulatedDelta += browserEvent.deltaY; - - if (gestureHasZoomModifiers) { - const deltaAbs = Math.ceil(Math.abs(gestureAccumulatedDelta / 5)); - const deltaDirection = gestureAccumulatedDelta > 0 ? -1 : 1; - const delta = deltaAbs * deltaDirection; - const newFontSize = this._clampFontSize(gestureStartFontSize + delta); - this._configurationService.updateValue(TerminalSettingId.FontSize, newFontSize); + prevMouseWheelTime = Date.now(); gestureAccumulatedDelta += browserEvent.deltaY; - browserEvent.preventDefault(); - browserEvent.stopPropagation(); - return false; + + if (gestureHasZoomModifiers) { + const deltaAbs = Math.ceil(Math.abs(gestureAccumulatedDelta / 5)); + const deltaDirection = gestureAccumulatedDelta > 0 ? -1 : 1; + const delta = deltaAbs * deltaDirection; + const newFontSize = this._clampFontSize(gestureStartFontSize + delta); + this._configurationService.updateValue(TerminalSettingId.FontSize, newFontSize); + gestureAccumulatedDelta += browserEvent.deltaY; + browserEvent.preventDefault(); + browserEvent.stopPropagation(); + return false; + } } } return true;