Question:
When you hover over a type in a TypeScript file, the tooltip that appears has a very low max width, making it difficult to read long type signatures.
I would include a screenshot but it's not easy to take a screenshot keeping the tooltip on screen!
! Errors are quite unreadable if the width does not adapt to the font size.
! it would be nice if the tip used the available space instead of wrapping at an arbitrary point in c# too
!
! Same problem using rust's language server.
General styling control would be very helpful. Also line-height. Another approach would be to have a bottom panel that displays the full error and the tooltip displays a shortened version.
!
! When using the auto import feature it is often impossible to differentiate whats what as the import path is cut off due to the limited width of the suggestions window.
Is this something we can adjust with custom css? It makes snippet infoormation very difficult to read as well. !
Same in Python. We have to jump through hoops trying to flow doc nicely. And when it appears OK on Windows, it breaks on Mac... ! And it is inconsistent. Ex, hover is OK ! But completion list decides to wrap. What gives? ! Looks like hover respects markdown while completion item doc is plain string and gets wrapped randomly.
!
Someone say long type signatures? !
Here is a workaround by hacking the file "C:Program FilesMicrosoft VS Coderesourcesappoutvsworkbench" Simply append the code above after the original content of file, and restart VSCode. (Title bar may alert a warning message "Not Supported" and hacked changes would be overridden by updating VSCode) !
It would be nice to have some control on the width. The above does work but vscode presents the message your installation may be corrupt on restarting.
Instead of hacking the CSS directly as mentioned above, I recommend using the to just override the current CSS. That way when VSCode updates, you can just reload the custom css file that you have specified (personally, I have a project where I hold configurations for my shell, Spacemacs, etc. and this custom CSS file goes there). Until it's officially supported, hacking the CSS is likely the best route. The suggested widths above were a bit much for me, so I settled on the following values for now:
What is preventing the devs from providing a configuration option for this? This issue has been open for almost 2 years, and it bugs me on a daily basis. Would love to see it fixed.
(since you seem like the most relevant person to ping) is anything likely to be done about this?
I would love to hear an explanation from devs too. What are the difficulties of implementing this? I imagine it's settings a dynamic max-width and adding some more lines to add it in Settings. Are there other design blockers?
Will you take a look at this? In 3 days it will be a 2 year anniversary for this simple feature request.
Assigned to and as I remember we are going to have some UX improvements for editor tooltips and so on.
maybe now is the time to take this on? current iteration tries to solve parameter hints ux and this is not that much different
! I employed CSS and put together full instructions: [Custom CSS and JS Loader extension][1] macOS VS Code: VS Code Insiders: Linux: : [1]: Restart VSCode Ignore "VSCode is corrupt" error You can choose to suppress this notice forever Run command "Reload Custom CSS and JS"
just as a disclaimer, if anyone modifies the CSS/JS of the app, it comes up at “corrupted” in diagnostic checks, and you’ll typically get pushback if you report issues and include diagnostic information. Or, at least, I received pushback when I had custom CSS/JS enabled, and wouldn’t receive help until I turned it off (even though it was harmless/not related to the issue I was having). While this is indeed an okay workaround, we should just keep making our voices heard so that this is natively supported.
100% agree. This is just a workaround. It's hard enough to read TypeScript lint as it is! :)
Currenlty using VSCode 1.30.2, followed instructions step by step, but it's not working. I don't even get the VSCode corrupt error. I'm running Windows 10 (V.1803). Edit: It was my mistake. For anyone who's having trouble, make sure to run Enable Custom CSS and JS from the command palette. Simply restarting won't work.
This issue seems to be fixed in 1.32.0-insider (1.32.0-insider) . I hope this is an intended behavior. I want to thank the developers.
This change is related to . I confirmed that the max width of is still small as mentioned above. <img width="867" alt="2019-02-22 17 06 19" src="https://user-"
Update: in , only the hovers for problems and the hovers with code blocks become to have larger width. Others have smaller width.
Hello there,your solution is great,but I want to ask how to get rid of the word at the title.As sort of OCD,sufferring from that. thx a lot!
This extension was created specifically for solving this:
This has been a long standing annoyance, with an issue that's like 2 and a half year ago. It shouldn't take much effort to have a config property that overrides the width/height of the tooltip, surely? Like, 10 mins of effort? <img width="525" alt="Screen Shot 2019-07-18 at 6 41 15 PM" src="https://user-"
if it's really 10 mins of effort, then I'm sure you can submit a PR for this? I definitely can't do this in anywhere close to 10 mins, so it would be much appreciated!
Seriously, I want instead of this: ! At least something like this (with syntax highlighting it will be even better): !
There's already been a PR. I really don't understand this. I figure most VScode devs develop VScode in VScode, are they comfortable with the current state?
fyi, it would be great if the hover could be resized
How is this issue 4 years old and such a basic thing still isn't implemented?
Is there any word on whether we could see this soon? The suggestion widget has had resizing enabled since v1.51 in October, 2020. Is this tooltip widget considerably harder to add this feature for or are there additional considerations to be made? Whether it's a click to resize, or a manual adjustment in settings, could we have an update on the status of this addition? Opening new editor tabs just to properly read code annotations for some more descriptive components on my large monitors does feel like an unnecessary extra step.
might be very related and close to what you did here:
Hi, Instead of configuring the max width as the title says, could the tooltip hover be resizable ? (Also check for more info on what was done with the suggest widget)
It's sad to see that it's still not a thing.. I would really like to adjust the height of hover description tooltips.. The big brother Visual Studio does a much better job already. Let VS Code catch up a little..
another possible view for this issue
It is 2022/11/11. Christmas is close and I made sure Santa knows what I want!
"Excuse me, it's 2023"
This one will be my favorite. Copilot suggestions and TS errors just can't be seen in this tooltip. It's time to fix it.
If this is still open and no one is looking at it, I'll take a crack at it. Feel free to assign it to me if that's alright.
Hey all, thank you for your patience. A PR has been made which is currently under work but nearing its completion. You may find it here: Once this PR is merged, you will be able to resize content hovers within Insiders.
Would you add "Reset Hover Widget Size" command in Command Palette? Like we have for suggest widget: "Reset Suggest Widget Size". It would be good if we could reset the size to the initial one.
Thank you very much. 1 Is it correct, that this would not stay across different sessions? 2 The default max width is very small, is there any consideration, of increasing that?
Will this feature also allow us to define the window size of a hover provider in a extension above the current limitations?
Hi if is is decided that the hover widget size should be configurable, there will be a command to clear the persisted sizes. This feature is still under discussion. Hi depending on the implementation, it is possible that the persisted sizes are persisted or not across different sessions. This is still under discussion. Currently the implementation is such that the maximum natural width is the same as before. Hi the current implementation does not provide this functionality. This could be addressed in a separate issue as it is related to the usage of the hover widget by extensions. The current PR that is worked on is the following:
Thanks a lot. And do you consider increasing the default size, that is unfitting to most real world scenarios? The windows is so small, that I feel the need to increase it even on my WXGA Laptop.
Hey all, thank you for the patience. A PR has been merged in order to make the content hover resizable. The change should be visible in tomorrow's VS Code insiders version and in the next stable release which will happen in the coming two weeks. There currently is no mechanism to save the content hover - we are discussing how best to approach it. You may track the issue on persisting the hover content here: we are currently not thinking about increasing the default maximum size. However it is possible that we implement the persisting mechanism as follows: when you increase the content hover size to a specific size, this size is persisted, and it is applied as maximum default size on the next hover appearances. This potential implementation is still under discussion by our team.
Just want to say thank you you seem to have been tackling a lot of these high-level nitpicks that have been in the VSCode backlog for years, and for that I am very appreciative.
I can't find a command to clear/reset hover widget size, is this has been ?
Hi currently the command does not exist because a persisting mechanism has not been put into place as of yet. It will appear when the latter is .
Oh okay, thanks a lot

<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IResizeEvent, ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IPosition } from 'vs/editor/common/core/position'; import { PositionAffinity } from 'vs/editor/common/model'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import * as dom from 'vs/base/browser/dom'; import { clamp } from 'vs/base/common/numbers'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Emitter, Event } from 'vs/base/common/event'; export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; constructor( private readonly _editor: ICodeEditor, private readonly _persistingOptions: IPersistingOptions, ) { console.log('Inside of ResizableWidget constructor'); this.element = new ResizableHTMLElement(); this.element.domNode.classList.add('editor-widget', 'resizable-widget'); if (this._persistingOptions instanceof SingleSizePersistingOptions) { this._persistingMechanism = new SingleSizePersistingMechanism(this, this.element, this._editor, this._persistingOptions); } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { this._persistingMechanism = new MultipleSizePersistingMechanism(this, this.element, this._editor); } else { throw new Error('Please specify a valid persisting mechanism'); } } dispose(): void { this._disposables.dispose(); this.element.dispose(); } resize(dimension: dom.Dimension): void { } hide(): void { this.element.clearSashHoverState(); } findMaximumRenderingHeight(): number | undefined { return Infinity; } findMaximumRenderingWidth(): number | undefined { return Infinity; } findPersistedSize(): dom.Dimension | undefined { return this._persistingMechanism.findSize(); } } export abstract class ResizableContentWidget implements IContentWidget { abstract ID: string; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { this.editor.addContentWidget(this); console.log('Inisde of ResizableContentWidget constructor'); } findPersistedSize(): dom.Dimension | undefined { return this.resizableWidget.findPersistedSize(); } getId(): string { console.log('this.ID : ', this.ID); return this.ID; } getDomNode(): HTMLElement { console.log('Inside of getDomNode of ResizableContentWidget'); console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); this.resizableWidget.element.domNode.style.zIndex = '49'; this.resizableWidget.element.domNode.style.position = 'fixed'; // this.resizableWidget.element.domNode.style.display = 'block'; return this.resizableWidget.element.domNode; } getPosition(): IContentWidgetPosition | null { console.log('Inside of getPosition of ResizableContentWidget'); const contentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, preference: (this._preference), positionAffinity: this._positionAffinity }; console.log('contentWidgetPosition: ', contentWidgetPosition); return contentWidgetPosition; } hide(): void { this.editor.layoutContentWidget(this); } set position(position: IPosition | null) { this._position = position; } set secondaryPosition(position: IPosition | null) { this._secondaryPosition = position; } set preference(preference: ContentWidgetPositionPreference[]) { this._preference = preference; } set positionAffinity(affinity: PositionAffinity | undefined) { this._positionAffinity = affinity; } } interface IPersistingOptions { } export class SingleSizePersistingOptions implements IPersistingOptions { constructor( public readonly key: string, public readonly defaultSize: dom.Dimension, @IStorageService public readonly storageService: IStorageService ) { } } export class MultipleSizePersistingOptions implements IPersistingOptions { constructor() { } } interface IPersistingMechanism extends IDisposable { findSize(): dom.Dimension | undefined; } // TODO: maybe need to make more generic, this is specific to the suggest widget class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSize: PersistedWidgetSize | null = null; private readonly _disposables = new DisposableStore(); constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, private readonly editor: ICodeEditor, private readonly persistingOptions: SingleSizePersistingOptions ) { this._persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService, this.editor); class ResizeState { constructor( readonly persistedSize: dom.Dimension | undefined, readonly currentSize: dom.Dimension, public persistHeight = false, public persistWidth = false, ) { } } let state: ResizeState | undefined; this._disposables.add(this.element.onDidWillResize(() => { // TODO: add back, this._contentWidget.lockPreference(); state = new ResizeState(this._persistedWidgetSize!.restore(), this.element.size); })); this._disposables.add(this.element.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; state.persistWidth = state.persistWidth || !!e.east || !!e.west; } if (!e.done) { return; } if (state) { const fontInfo = this.editor.getOption(EditorOption.fontInfo); const itemHeight = clamp(this.editor.getOption(EditorOption.suggestLineHeight) || fontInfo.lineHeight, 8, 1000); const threshold = Math.round(itemHeight / 2); let { width, height } = this.element.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; } if (!state.persistWidth || Math.abs(state.currentSize.width - width) <= threshold) { width = state.persistedSize?.width ?? this.persistingOptions.defaultSize.width; } this._persistedWidgetSize!.store(new dom.Dimension(width, height)); } // TODO: add back, reset working state // this._contentWidget.unlockPreference(); state = undefined; })); } findSize(): dom.Dimension | undefined { return undefined; } dispose(): void { this._disposables.dispose(); } } class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSizes: ResourceMap<Map<string, dom.Dimension>> = new ResourceMap<Map<string, dom.Dimension>>(); private readonly _disposables = new DisposableStore(); private _tooltipPosition: IPosition | null = null; // TODO: not sure if I need the following // private _initialHeight: number = 0; // private _initialTop: number = 0; private _resizing: boolean = false; private _size: dom.Dimension | undefined = undefined; private _maxRenderingHeight: number | undefined = Infinity; private _maxRenderingWidth: number | undefined = Infinity; private readonly _onDidResize = new Emitter<IResizeEvent>(); readonly onDidResize: Event<IResizeEvent> = this._onDidResize.event; // private _renderingAbove: ContentWidgetPositionPreference | undefined = undefined; constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, public readonly editor: ICodeEditor ) { this.element.minSize = new dom.Dimension(10, 24); this._disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; if (!uri || !this._persistedWidgetSizes.has(uri)) { return; } const persistedSizesForUri = this._persistedWidgetSizes.get(uri)!; const updatedPersistedSizesForUri = new Map<string, dom.Dimension>(); for (const change of e.changes) { const changeOffset = change.rangeOffset; const rangeLength = change.rangeLength; const endOffset = changeOffset + rangeLength; const textLength = change.text.length; for (const key of persistedSizesForUri.keys()) { const parsedKey = JSON.parse(key); const tokenOffset = parsedKey[0]; const tokenLength = parsedKey[1]; if (endOffset < tokenOffset) { const oldSize = persistedSizesForUri.get(key)!; const newKey: [number, number] = [tokenOffset - rangeLength + textLength, tokenLength]; updatedPersistedSizesForUri.set(JSON.stringify(newKey), oldSize); } else if (changeOffset >= tokenOffset + tokenLength) { updatedPersistedSizesForUri.set(key, persistedSizesForUri.get(key)!); } } } this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); this._disposables.add(this.element.onDidWillResize(() => { this._resizing = true; // this._initialHeight = this.element.domNode.clientHeight; // this._initialTop = this.element.domNode.offsetTop; })); this._disposables.add(this.element.onDidResize(e => { let height = e.dimension.height; let width = e.dimension.width; const maxWidth = this.element.maxSize.width; const maxHeight = this.element.maxSize.height; width = Math.min(maxWidth, width); height = Math.min(maxHeight, height); if (!this._maxRenderingHeight) { return; } this._size = new dom.Dimension(width, height); this.element.layout(height, width); // Calling the resize function of the this.resizableWidget.resize(new dom.Dimension(width, height)); // Update the top parameters only when we decided to render above // TODO: presumably do not need to resize the element // if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { // 	this.element.domNode.style.top = this._initialTop - (height - this._initialHeight) + 'px'; // } // const horizontalSashWidth = width - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.northSash.el.style.width = horizontalSashWidth; // this.element.southSash.el.style.width = horizontalSashWidth; // const verticalSashWidth = height - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.eastSash.el.style.height = verticalSashWidth; // this.element.westSash.el.style.height = verticalSashWidth; // this.element.eastSash.el.style.top = TOTAL_BORDER_WIDTH + 'px'; // Fire the current dimension // TODO: probably don't need to listen on the firing event? // this._onDidResize.fire({ dimension: this._size, done: false }); this._maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); // this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(this._renderingAbove); if (!this._maxRenderingHeight || !this._maxRenderingWidth) { return; } this.element.maxSize = new dom.Dimension(this._maxRenderingWidth, this._maxRenderingHeight); // Persist the height only when the resizing has stopped if (e.done) { if (!this.editor.hasModel()) { return; } const uri = this.editor.getModel().uri; if (!uri || !this._tooltipPosition) { return; } const persistedSize = new dom.Dimension(width, height); const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; // Suppose that the uri does not exist in the persisted widget hover sizes, then create a map if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map<string, dom.Dimension>([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); this._persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); } else { const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } this._resizing = false; } // this.editor.layoutOverlayWidget(this); // this.editor.render(); })); } set tooltipPosition(position: IPosition) { this._tooltipPosition = position; } findSize(): dom.Dimension | undefined { console.log('Inside of findSize of the MultiplePersistingMechanisms'); if (!this._tooltipPosition || !this.editor.hasModel()) { return; } const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; const uri = this.editor.getModel().uri; const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; } return persistedSizesForUri.get(JSON.stringify([offset, length])); } dispose(): void { this._disposables.dispose(); } } class PersistedWidgetSize { constructor( private readonly _key: string, private readonly _service: IStorageService, editor: ICodeEditor ) { } restore(): dom.Dimension | undefined { const raw = this._service.get(this._key, StorageScope.PROFILE) ?? ''; try { const obj = JSON.parse(raw); if (dom.Dimension.is(obj)) { return dom.Dimension.lift(obj); } } catch { // ignore } return undefined; } store(size: dom.Dimension) { this._service.store(this._key, JSON.stringify(size), StorageScope.PROFILE, StorageTarget.MACHINE); } reset(): void { this._service.remove(this._key, StorageScope.PROFILE); } } </ins>


Question:
When you hover over a type in a TypeScript file, the tooltip that appears has a very low max width, making it difficult to read long type signatures.
I would include a screenshot but it's not easy to take a screenshot keeping the tooltip on screen!
! Errors are quite unreadable if the width does not adapt to the font size.
! it would be nice if the tip used the available space instead of wrapping at an arbitrary point in c# too
!
! Same problem using rust's language server.
General styling control would be very helpful. Also line-height. Another approach would be to have a bottom panel that displays the full error and the tooltip displays a shortened version.
!
! When using the auto import feature it is often impossible to differentiate whats what as the import path is cut off due to the limited width of the suggestions window.
Is this something we can adjust with custom css? It makes snippet infoormation very difficult to read as well. !
Same in Python. We have to jump through hoops trying to flow doc nicely. And when it appears OK on Windows, it breaks on Mac... ! And it is inconsistent. Ex, hover is OK ! But completion list decides to wrap. What gives? ! Looks like hover respects markdown while completion item doc is plain string and gets wrapped randomly.
!
Someone say long type signatures? !
Here is a workaround by hacking the file "C:Program FilesMicrosoft VS Coderesourcesappoutvsworkbench" Simply append the code above after the original content of file, and restart VSCode. (Title bar may alert a warning message "Not Supported" and hacked changes would be overridden by updating VSCode) !
It would be nice to have some control on the width. The above does work but vscode presents the message your installation may be corrupt on restarting.
Instead of hacking the CSS directly as mentioned above, I recommend using the to just override the current CSS. That way when VSCode updates, you can just reload the custom css file that you have specified (personally, I have a project where I hold configurations for my shell, Spacemacs, etc. and this custom CSS file goes there). Until it's officially supported, hacking the CSS is likely the best route. The suggested widths above were a bit much for me, so I settled on the following values for now:
What is preventing the devs from providing a configuration option for this? This issue has been open for almost 2 years, and it bugs me on a daily basis. Would love to see it fixed.
(since you seem like the most relevant person to ping) is anything likely to be done about this?
I would love to hear an explanation from devs too. What are the difficulties of implementing this? I imagine it's settings a dynamic max-width and adding some more lines to add it in Settings. Are there other design blockers?
Will you take a look at this? In 3 days it will be a 2 year anniversary for this simple feature request.
Assigned to and as I remember we are going to have some UX improvements for editor tooltips and so on.
maybe now is the time to take this on? current iteration tries to solve parameter hints ux and this is not that much different
! I employed CSS and put together full instructions: [Custom CSS and JS Loader extension][1] macOS VS Code: VS Code Insiders: Linux: : [1]: Restart VSCode Ignore "VSCode is corrupt" error You can choose to suppress this notice forever Run command "Reload Custom CSS and JS"
just as a disclaimer, if anyone modifies the CSS/JS of the app, it comes up at “corrupted” in diagnostic checks, and you’ll typically get pushback if you report issues and include diagnostic information. Or, at least, I received pushback when I had custom CSS/JS enabled, and wouldn’t receive help until I turned it off (even though it was harmless/not related to the issue I was having). While this is indeed an okay workaround, we should just keep making our voices heard so that this is natively supported.
100% agree. This is just a workaround. It's hard enough to read TypeScript lint as it is! :)
Currenlty using VSCode 1.30.2, followed instructions step by step, but it's not working. I don't even get the VSCode corrupt error. I'm running Windows 10 (V.1803). Edit: It was my mistake. For anyone who's having trouble, make sure to run Enable Custom CSS and JS from the command palette. Simply restarting won't work.
This issue seems to be fixed in 1.32.0-insider (1.32.0-insider) . I hope this is an intended behavior. I want to thank the developers.
This change is related to . I confirmed that the max width of is still small as mentioned above. <img width="867" alt="2019-02-22 17 06 19" src="https://user-"
Update: in , only the hovers for problems and the hovers with code blocks become to have larger width. Others have smaller width.
Hello there,your solution is great,but I want to ask how to get rid of the word at the title.As sort of OCD,sufferring from that. thx a lot!
This extension was created specifically for solving this:
This has been a long standing annoyance, with an issue that's like 2 and a half year ago. It shouldn't take much effort to have a config property that overrides the width/height of the tooltip, surely? Like, 10 mins of effort? <img width="525" alt="Screen Shot 2019-07-18 at 6 41 15 PM" src="https://user-"
if it's really 10 mins of effort, then I'm sure you can submit a PR for this? I definitely can't do this in anywhere close to 10 mins, so it would be much appreciated!
Seriously, I want instead of this: ! At least something like this (with syntax highlighting it will be even better): !
There's already been a PR. I really don't understand this. I figure most VScode devs develop VScode in VScode, are they comfortable with the current state?
fyi, it would be great if the hover could be resized
How is this issue 4 years old and such a basic thing still isn't implemented?
Is there any word on whether we could see this soon? The suggestion widget has had resizing enabled since v1.51 in October, 2020. Is this tooltip widget considerably harder to add this feature for or are there additional considerations to be made? Whether it's a click to resize, or a manual adjustment in settings, could we have an update on the status of this addition? Opening new editor tabs just to properly read code annotations for some more descriptive components on my large monitors does feel like an unnecessary extra step.
might be very related and close to what you did here:
Hi, Instead of configuring the max width as the title says, could the tooltip hover be resizable ? (Also check for more info on what was done with the suggest widget)
It's sad to see that it's still not a thing.. I would really like to adjust the height of hover description tooltips.. The big brother Visual Studio does a much better job already. Let VS Code catch up a little..
another possible view for this issue
It is 2022/11/11. Christmas is close and I made sure Santa knows what I want!
"Excuse me, it's 2023"
This one will be my favorite. Copilot suggestions and TS errors just can't be seen in this tooltip. It's time to fix it.
If this is still open and no one is looking at it, I'll take a crack at it. Feel free to assign it to me if that's alright.
Hey all, thank you for your patience. A PR has been made which is currently under work but nearing its completion. You may find it here: Once this PR is merged, you will be able to resize content hovers within Insiders.
Would you add "Reset Hover Widget Size" command in Command Palette? Like we have for suggest widget: "Reset Suggest Widget Size". It would be good if we could reset the size to the initial one.
Thank you very much. 1 Is it correct, that this would not stay across different sessions? 2 The default max width is very small, is there any consideration, of increasing that?
Will this feature also allow us to define the window size of a hover provider in a extension above the current limitations?
Hi if is is decided that the hover widget size should be configurable, there will be a command to clear the persisted sizes. This feature is still under discussion. Hi depending on the implementation, it is possible that the persisted sizes are persisted or not across different sessions. This is still under discussion. Currently the implementation is such that the maximum natural width is the same as before. Hi the current implementation does not provide this functionality. This could be addressed in a separate issue as it is related to the usage of the hover widget by extensions. The current PR that is worked on is the following:
Thanks a lot. And do you consider increasing the default size, that is unfitting to most real world scenarios? The windows is so small, that I feel the need to increase it even on my WXGA Laptop.
Hey all, thank you for the patience. A PR has been merged in order to make the content hover resizable. The change should be visible in tomorrow's VS Code insiders version and in the next stable release which will happen in the coming two weeks. There currently is no mechanism to save the content hover - we are discussing how best to approach it. You may track the issue on persisting the hover content here: we are currently not thinking about increasing the default maximum size. However it is possible that we implement the persisting mechanism as follows: when you increase the content hover size to a specific size, this size is persisted, and it is applied as maximum default size on the next hover appearances. This potential implementation is still under discussion by our team.
Just want to say thank you you seem to have been tackling a lot of these high-level nitpicks that have been in the VSCode backlog for years, and for that I am very appreciative.
I can't find a command to clear/reset hover widget size, is this has been ?
Hi currently the command does not exist because a persisting mechanism has not been put into place as of yet. It will appear when the latter is .
Oh okay, thanks a lot

<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import * as dom from 'vs/base/browser/dom'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { PositionAffinity } from 'vs/editor/common/model'; import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; const SCROLLBAR_WIDTH = 10; // TODO: maybe don't need the resizable widget class export class ResizableHoverWidget extends ResizableWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); // The ContentWidget is a child of the resizable widget private resizableContentWidget: ResizableContentHoverWidget; public readonly allowEditorOverflow = true; public readonly _hover: HoverWidget = this.hoverDisposables.add(new HoverWidget()); private readonly editor: ICodeEditor; private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); private readonly _focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); private readonly _horizontalScrollingBy: number = 30; private _visibleData: ContentHoverVisibleData | null = null; private _renderingAbove: ContentWidgetPositionPreference; constructor( editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { super(editor, new MultipleSizePersistingOptions()); this.editor = editor; // create here the dom node and all other logic should go here that was in the super abstract class this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); this._renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; this.hoverDisposables.add(this.element.onDidResize((e) => { // When the resizable hover overlay changes, resize the widget // this._widget.resize(e.dimension); })); this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); this.hoverDisposables.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); this._setVisibleData(null); this._layout(); this.hoverDisposables.add(this._focusTracker.onDidFocus(() => { this._hoverFocusedKey.set(true); })); this.hoverDisposables.add(this._focusTracker.onDidBlur(() => { this._hoverFocusedKey.set(false); })); dom.append(this.element.domNode, this._hover.containerDomNode); } public get position(): Position | null { return this._visibleData?.showAtPosition ?? null; } public get isColorPickerVisible(): boolean { return Boolean(this._visibleData?.colorPicker); } public get isVisibleFromKeyboard(): boolean { return (this._visibleData?.source === HoverStartSource.Keyboard); } public get isVisible(): boolean { return this._hoverVisibleKey.get() ?? false; } public get renderingAbove(): ContentWidgetPositionPreference { return this._renderingAbove; } public set renderingAbove(renderingAbove: ContentWidgetPositionPreference) { this._renderingAbove = renderingAbove; } // NEW public override resize(size: dom.Dimension) { console.log('Inside of resize'); // Removing the max height and max width here - the max size is controlled by the resizable overlay this._hover.contentsDomNode.style.maxHeight = 'none'; this._hover.contentsDomNode.style.maxWidth = 'none'; const width = size.width + 'px'; // const width = size.width - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; this._hover.containerDomNode.style.width = width; this._hover.contentsDomNode.style.width = width; // const height = size.height - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; const height = size.height + 'px'; this._hover.containerDomNode.style.height = height; this._hover.contentsDomNode.style.height = height; const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; } this._hover.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } this._hover.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); } public override findMaximumRenderingHeight(): number | undefined { if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { availableSpace = editorBox.top + mouseBox.top - 30; } else { const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; availableSpace = bodyBox.height - mouseBottom; } let divMaxHeight = 0; for (const childHtmlElement of this._hover.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } if (this._hover.contentsDomNode.clientWidth < this._hover.contentsDomNode.scrollWidth) { divMaxHeight += SCROLLBAR_WIDTH; } return Math.min(availableSpace, divMaxHeight); } public findMaxRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const widthOfEditor = editorBox.width; const leftOfEditor = editorBox.left; const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; const leftOfContainer = this._hover.containerDomNode.offsetLeft; return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } public override dispose(): void { this.editor.removeContentWidget(this.resizableContentWidget); if (this._visibleData) { this._visibleData.disposables.dispose(); } super.dispose(); } public getDomNode() { return this._hover.containerDomNode; } public getContentsDomNode() { return this._hover.contentsDomNode; } public isMouseGettingCloser(posx: number, posy: number): boolean { if (!this._visibleData) { return false; } if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { this._visibleData.initialMousePosX = posx; this._visibleData.initialMousePosY = posy; return false; } const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); if (typeof this._visibleData.closestMouseDistance === 'undefined') { this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); return true; } private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { if (this._visibleData) { this._visibleData.disposables.dispose(); } this._visibleData = visibleData; this._hoverVisibleKey.set(!!this._visibleData); this._hover.containerDomNode.classList.toggle('hidden', !this._visibleData); } private _layout(): void { const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; this._hover.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; this._hover.contentsDomNode.style.maxHeight = `${height}px`; this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); codeClasses.forEach(node => this.editor.applyFontInfo(node)); } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); if (!this.editor || !this.editor.hasModel()) { return; } this._setVisibleData(visibleData); this._hover.contentsDomNode.textContent = ''; this._hover.contentsDomNode.appendChild(node); this._hover.contentsDomNode.style.paddingBottom = ''; this._updateFont(); const containerDomNode = this.resizableContentWidget.getDomNode(); let height; // If the persisted size has already been found then set a maximum height and width if (!persistedSize) { this._hover.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this.editor.render(); height = containerDomNode.clientHeight; } // When there is a persisted size then do not use a maximum height or width else { this._hover.contentsDomNode.style.maxHeight = 'none'; this._hover.contentsDomNode.style.maxWidth = 'none'; height = persistedSize.height; } // The dimensions of the document in which we are displaying the hover const bodyBox = dom.getClientArea(document.body); // Hard-coded in the hover.css file as 1.5em or 24px const minHeight = 24; // The full height is already passed in as a parameter const fullHeight = height; const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position const availableSpaceBelow = bodyBox.height - mouseBottom; // Max height below is the minimum of the available space below and the full height of the widget const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor const availableSpaceAbove = editorBox.top + mouseBox.top - 30; const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); // We find the maximum height of the widget possible on the top or on the bottom const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); if (height < minHeight) { height = minHeight; } if (height > maxHeight) { height = maxHeight; } // Determining whether we should render above or not ideally if (this.editor.getOption(EditorOption.hover).above) { this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; } else { this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!persistedSize) { this.onContentsChanged(); } if (visibleData.stoleFocus) { this._hover.containerDomNode.focus(); } visibleData.colorPicker?.layout(); if (!this._visibleData) { return; } const clientHeight = this._hover.containerDomNode.clientHeight; const clientWidth = this._hover.containerDomNode.clientWidth; this.element.layout(clientHeight, clientWidth); this.resizableContentWidget.position = this._visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this._renderingAbove]; this.resizableContentWidget.positionAffinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); console.log('At the end of showAt'); } public override hide(): void { this.element.clearSashHoverState(); if (this._visibleData) { const stoleFocus = this._visibleData.stoleFocus; this._setVisibleData(null); this.editor.layoutContentWidget(this.resizableContentWidget); if (stoleFocus) { this.editor.focus(); } } } // NEW public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { console.log('Inside of onContentsChanged'); const containerDomNode = this.getDomNode(); const contentsDomNode = this.getContentsDomNode(); // Suppose a persisted size is defined if (persistedSize) { const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width); //  - SASH_WIDTH // const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height); // SASH_WIDTH // Already setting directly the height and width parameters containerDomNode.style.width = widthMinusSash + 'px'; containerDomNode.style.height = heightMinusSash + 'px'; contentsDomNode.style.width = widthMinusSash + 'px'; contentsDomNode.style.height = heightMinusSash + 'px'; } else { // Otherwise the height and width are set to auto containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; } this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // There is just a horizontal scrollbar const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. if (persistedSize && maxRenderingHeight) { containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height) + 'px'; //  - SASH_WIDTH contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SCROLLBAR_WIDTH) + 'px'; //  - SASH_WIDTH reposition = true; } if (reposition) { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); } } } // OLD FUNCTION /* public onContentsChanged(): void { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // There is just a horizontal scrollbar const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); } } } */ public clear(): void { this._hover.contentsDomNode.textContent = ''; } public focus(): void { this._hover.containerDomNode.focus(); } public scrollUp(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); } public scrollDown(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); } public scrollLeft(): void { const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); } public scrollRight(): void { const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); } public pageUp(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); } public pageDown(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); } public goToTop(): void { this._hover.scrollbar.setScrollPosition({ scrollTop: 0 }); } public goToBottom(): void { this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); } public escape(): void { this.editor.focus(); } } export class ResizableContentHoverWidget extends ResizableContentWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget, editor); console.log('Inside of resizable content hover widget'); } } class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; constructor( public readonly colorPicker: IEditorHoverColorPickerWidget | null, public readonly showAtPosition: Position, public readonly showAtSecondaryPosition: Position, public readonly preferAbove: boolean, public readonly stoleFocus: boolean, public readonly source: HoverStartSource, public readonly isBeforeContent: boolean, public initialMousePosX: number | undefined, public initialMousePosY: number | undefined, public readonly disposables: DisposableStore ) { } } function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { const x = (left + width / 2); // x center of rectangle const y = (top + height / 2); // y center of rectangle const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); return Math.sqrt(dx * dx + dy * dy); } </ins>


Question:
VSCode Version: 1.7.2 () OS Version: Windows 10.0. Steps to Reproduce: a file a sentence of text such as Lorem ipsum sit dolar amet. your keyboard cursor after <kbdTab</kbdExpected: Spaces or tabs to be between and Result: word gets converted into an XML tag and auto closed, leaving us with <Lorem</Loremipsum sit dolar amet. !
This is coming from Emmet. To disable this, add: to your settings. Although this is currently the expected behavior, I think we should probably disable emmet expansions in markdown by default because this behavior can be annoying during normal writing. Any thoughts?
this behaviour is a consequence of , which has as the goal to not hard code in which language modes emmet is enabled for. As a heuristic uses the grammar's scope name hierarchy as a hint. This heuristic has worked pretty well. The scope of the markdown grammar is . This means Markdown is treated as a specialization of and since emmets supports , is enabled in Markdown as well. According the emmet doc there is no special syntax profile available for Markdown So a quick fix would be to: hard code an exclusion for markdown in #isEmmetEnableMode change the scope name of the markdown grammar, so that it doesn't inherit from html, not sure what the consequences of this are. do you have other ideas how to improve the support for emmet in Markdown and avoid the surprise described in this issue?
Hello, I see the same way as you suggested above. But, perhaps, we can also disable Markdown in the settings, as it was for . If you decide to disable Emmet inside Markdown, it is better to first option. But my 2 cents: Markdown is a lightweight markup language and it presupposes the existence of HTML constructs within yourself. Thus, it seems to me, to disable Emmet inside Markdown is not correct. P.S. Small news: the creator of Emmet had already started work on the second version aka 2.0.0
thanks for the feedback. I agree with your point that disabling emmet without some way to re-enable it, if someone really wants emmet is better than to totally disable it. Glad to hear about Emmet 2.0.
Could just be in the default setting for ? That would stop most users from triggering emmet unexpectedly in markdown files, while still allowing users to opt back in to emmet for markdown if they wish
the idea is good. It has a small drawback. If someone defines in the settings, then they will not profit from this fix. However, if someone if familiar with this setting and then they know how to disable emmet in markdown, if they are annoyed by it. Bottom line I'm fine with this fix.
Ok, I've merged in which adds to the default list of excluded languages. Not a perfect solution, but it should stop many users from hitting this behavior unexpectedly

}, 'emmet.excludeLanguages': { 'type': 'array', <del> 'default': [], </del> <ins> 'default': ['markdown'], </ins> 'description': nls.localize('emmetExclude', "An array of languages where emmet abbreviations should not be expanded.") }, }


Question:
VSCode Version: Code - Insiders 1.8.0-insider (, 2016-12-06T16:53:46.634Z) OS Version: Darwin x64 15.6.0 Testing The current message seems to general: "For better performance exclude folders with many files." "better performance" is to weak because the typescript server basically shutdown and won't provide any of the advanced features. "folders with many files" is vague, it should mention JavaScript/TypeScript files that the user does not work on (like packages/libraries). could also mention that this happens in the js-, that would set the right expectation for the 'Configure Excludes' button and also inform the user how this can be done manually. Needs more thought: "Too many JavaScript/TypeScript files: To enable advanced editor features in JavaScript/TypeScript files exclude large folders with source files you do not work on." /cc
Also, the status bar button might benefit from being specific about the language it refers to.

public show(configFileName: string, largeRoots: string, onExecute: () => void) { this._currentHint = { message: largeRoots.length > 0 <del> ? localize('hintExclude', "For better performance exclude folders with many files, like: {0}", largeRoots) : localize('hintExclude.generic', "For better performance exclude folders with many files."), </del> <ins> ? localize('hintExclude', "To enable JavaScript/TypeScript IntelliSense, exclude folders with many files, like: {0}", largeRoots) : localize('hintExclude.generic', "To enable JavaScript/TypeScript IntelliSense, exclude large folders with source files that you do not work on."), </ins> options: [{ title: localize('open', "Configure Excludes"), execute: () => {


Question:
VSCode Version: Code - Insiders 1.8.0-insider (, 2016-12-06T16:53:46.634Z) OS Version: Darwin x64 15.6.0 Testing The current message seems to general: "For better performance exclude folders with many files." "better performance" is to weak because the typescript server basically shutdown and won't provide any of the advanced features. "folders with many files" is vague, it should mention JavaScript/TypeScript files that the user does not work on (like packages/libraries). could also mention that this happens in the js-, that would set the right expectation for the 'Configure Excludes' button and also inform the user how this can be done manually. Needs more thought: "Too many JavaScript/TypeScript files: To enable advanced editor features in JavaScript/TypeScript files exclude large folders with source files you do not work on." /cc
Also, the status bar button might benefit from being specific about the language it refers to.

}; this._item.tooltip = this._currentHint.message; this._item.text = localize('large.label', "Configure Excludes"); <del> this._item.tooltip = localize('hintExclude.tooltip', "For better performance exclude folders with many files."); </del> <ins> this._item.tooltip = localize('hintExclude.tooltip', "To enable JavaScript/TypeScript IntelliSense, exclude large folders with source files that you do not work on."); </ins> this._item.color = '#A5DF3B'; this._item.show(); this._client.logTelemetry('js.hintProjectExcludes');


Question:
VSCode Version: Code - Insiders 1.9.0-insider (, 2017-01-20T14:58:38.006Z) OS Version: Linux x64 4.8.0-34-generic Extensions: TypeScript file: ! Press enter: !
verified.

} else if (enterAction.indentAction === IndentAction.Indent) { // Indent once <del> executeCommand = TypeOperations.typeCommand(range, beforeText + 'n' + config.normalizeIndentation(indentation + 't' + enterAction.appendText), keepPosition); </del> <ins> executeCommand = TypeOperations.typeCommand(range, beforeText + 'n' + config.normalizeIndentation(indentation + enterAction.appendText), keepPosition); </ins> } else if (enterAction.indentAction === IndentAction.IndentOutdent) { // Ultra special let normalIndent = config.normalizeIndentation(indentation); <del> let increasedIndent = config.normalizeIndentation(indentation + 't' + enterAction.appendText); </del> <ins> let increasedIndent = config.normalizeIndentation(indentation + enterAction.appendText); </ins> let typeText = beforeText + 'n' + increasedIndent + 'n' + normalIndent;


Question:
VSCode Version: Code - Insiders 1.9.0-insider (, 2017-01-20T14:58:38.006Z) OS Version: Linux x64 4.8.0-34-generic Extensions: TypeScript file: ! Press enter: !
verified.

if (!enterResult) { enterResult = { indentAction: IndentAction.None, appendText: '' }; } else { <ins> // Here we add `t` to appendText first because enterAction is leveraging appendText and removeText to change indentation. </ins> if (!enterResult.appendText) { <del> enterResult.appendText = ''; </del> <ins> if ( (enterResult.indentAction === IndentAction.Indent) || (enterResult.indentAction === IndentAction.IndentOutdent) ) { enterResult.appendText = 't'; } else { enterResult.appendText = ''; } </ins> } }


Question:
Particularly on Windows, should be called to terminate the process. This will ensure the sockets are closed and the pty agent is shutdown.
Closing in favor of

}); ptyProcess.on('exit', function (exitCode) { <ins> ptyProcess.kill(); </ins> process.exit(exitCode); });


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

const pathSeparatorClause = '/'; const excludedPathCharactersClause = '[^0s!$`&*()[]+'":;]'; // '":; are allowed in paths but they are often separators so ignore them const escapedExcludedPathCharactersClause = '(s|!|$|`|&|*|(|)|+)'; <del> /** A regex that matches paths in the form /path, ~/path, ./path, ../path */ const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); const winPathPrefix = '([a-zA-Z]:|..?|~)'; </del> <ins> /** A regex that matches paths in the form /foo, ~/foo, ./foo, ../foo, foo/bar */ const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('((' + pathPrefix + '|(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); const winDrivePrefix = '[a-zA-Z]:'; const winPathPrefix = '(' + winDrivePrefix + '|..?|~)'; </ins> const winPathSeparatorClause = '(|/)'; const winExcludedPathCharactersClause = '[^0<>?|/s!$`&*()[]+'":;]'; <del> /** A regex that matches paths in the form c:path, ~path, .path */ const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); </del> <ins> /** A regex that matches paths in the form c:foo, ~foo, .foo, ..foo, foobar */ const WINDOWS_LOCAL_LINK_REGEX = new RegExp('((' + winPathPrefix + '|(' + winExcludedPathCharactersClause + ')+)?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); </ins> /** Higher than local link, lower than hypertext */ const CUSTOM_LINK_PRIORITY = -1; /** Lowest */


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

}); } <del> private _resolvePath(link: string): TPromise<string> { </del> <ins> protected _preprocessPath(link: string): string { </ins> if (this._platform === platform.Platform.Windows) { // Resolve ~ -> %HOMEDRIVE%%HOMEPATH% if (link.charAt(0) === '~') { if (!process.env.HOMEDRIVE || !process.env.HOMEPATH) { <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = `${process.env.HOMEDRIVE}${process.env.HOMEPATH + link.substring(1)}`; } <del> } else { // Resolve workspace path . / .. -> <path>/. / <path/.. if (link.charAt(0) === '.') { if (!this._contextService.hasWorkspace) { </del> <ins> // Resolve relative paths (.a, ..a, ~a, ab) if (!link.match('^' + winDrivePrefix)) { if (!this._contextService.hasWorkspace()) { </ins> // Abort if no workspace is open <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = path.join(this._contextService.getWorkspace().resource.fsPath, link); } } <del> // Resolve workspace path . / .. -> <path>/. / <path/.. if (link.charAt(0) === '.') { if (!this._contextService.hasWorkspace) { </del> <ins> // Resolve workspace path . | .. | <relative_path> -> <path>/. | <path>/.. | <path>/<relative_path> else if (link.charAt(0) !== '/' && link.charAt(0) !== '~') { if (!this._contextService.hasWorkspace()) { </ins> // Abort if no workspace is open <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = path.join(this._contextService.getWorkspace().resource.fsPath, link); } <ins> return link; } private _resolvePath(link: string): TPromise<string> { link = this._preprocessPath(link); if (!link) { return TPromise.as(void 0); } </ins> // Open an editor if the path exists return pfs.fileExists(link).then(isFile => {


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

import * as assert from 'assert'; import { Platform } from 'vs/base/common/platform'; import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; <ins> import { IWorkspace, WorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; import * as path from 'path'; import * as sinon from 'sinon'; </ins> class TestTerminalLinkHandler extends TerminalLinkHandler { public get localLinkRegex(): RegExp { return this._localLinkRegex; } <ins> public preprocessPath(link: string): string { return this._preprocessPath(link); } </ins> } class TestXterm {


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

public setHypertextValidationCallback() { } } <ins> class TestURI extends URI { constructor(private _fakePath: string) { super(); }; get fsPath(): string { return this._fakePath; } } class TestWorkspace implements IWorkspace { resource: URI; constructor(basePath: string) { this.resource = new TestURI(basePath); } } </ins> suite('Workbench - TerminalLinkHandler', () => { suite('localLinkRegex', () => { test('Windows', () => {


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

testLink('c:/a/long/path'); testLink('c:alongpath'); testLink('c:mixed/slashpath'); <ins> testLink('a/relative/path'); </ins> }); test('Linux', () => {


Question:
<!-- Do you have a question? Please ask it on --- VSCode Version: 1.10.2 OS Version: Mac OSX (10.11.6) Steps to Reproduce: VS Code integrated terminal a relative path (eg. ) Description: Let's say you have a build system that outputs a stack trace on a build error or failed test. If this was run from the integrated terminal, the file paths in the output should be included as clickable links which can be clicked to open the file in VSCode. However, this only works if the path is either an absolute path (e.g. ) or a relative path that begins with "./". Many build systems and tools output file paths relative to the directory the command was run, without the leading "./", Karma for example. So the output would be something like: , not . The first is not matched by VSCode as an openable path, but the second is. I believe that what is determined to be a path comes from the Regex in "" Is there a reason why relative paths of this form (e.g. no leading "./") are not included?
The reason was because until 1.11 links aren't validated so there would be heaps of false positives. Performance was also a factor but it shouldn't impact that much really now that I think about it. Now that links are validated maybe we should be more lenient when linkifying.
I'll assign this to April but if someone wants to do a PR before then you're welcome. You will need to: Modify the regex to allow paths that are not qualified with , , etc. Make sure that the new path matcher does not conflict with previously matched links and does not create links with adjacent characters. Eg. we want to avoid this:
Nice. I'll write a PR...
That would be awesome :+1:
Fixed in

testLink('./foo'); testLink('../foo'); testLink('/a/long/path'); <ins> testLink('a/relative/path'); }); }); suite('preprocessPath', () => { test('Windows', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Windows, null, new WorkspaceContextService(new TestWorkspace('C:base'))); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '' + arg2; }); assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:base./src/file1'); assert.equal(linkHandler.preprocessPath('srcfile2'), 'C:basesrcfile2'); assert.equal(linkHandler.preprocessPath('C:absolutepathfile3'), 'C:absolutepathfile3'); stub.restore(); }); test('Linux', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null, new WorkspaceContextService(new TestWorkspace('/base'))); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '/' + arg2; }); assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/./src/file1'); assert.equal(linkHandler.preprocessPath('src/file2'), '/base/src/file2'); assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3'); stub.restore(); }); test('No Workspace', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null, new WorkspaceContextService(null)); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3'); </ins> }); }); });  No newline at end of file


Question:
VSCode Version: Code - Insiders 1.11.0-insider (, 2017-03-17T08:14:15.805Z) OS Version: Windows_NT ia32 10.0. Extensions: ; Steps to Reproduce: a terminal and run "bash" with a text file containing some lines of text ctrl+v (or right-click) to paste some lines of text What's expected: The text should be appended before the cursor, and the existing text should be there after the cursor. What happens: Existing text disappears, and it seems some extra newlines are when pasting text. Note: there is no such problem when doing the exact same steps with This happens on insider builds, no idea if it happens with standard builds as well.
More information. Here is what happens when I try to paste this text function startagent { echo "Initialising new SSH agent..." /usr/bin/ssh-agent | sed 's/^echo/#echo/' "${SSHENV}" echo succeeded chmod 600 "${SSHENV}" . "${SSHENV}" /dev/null /usr/bin/ssh-add; } In the middle of a file containing this text: existing file with some text Here is what happens with (that's what expected: text is pasted in between existing text): ! Here is what happens with VSCode: text is pasted with extra newlines plus existing text appears in the middle of the pasted text !
Any update on this bug ?
Thanks for the ping. I've validated it's definitely an upstream issue. I tried to fix it a couple of days ago but didn't get anywhere. I'd guess it's related to node-pty or winpty as different shells appeared to handle it differently. It also seemed somewhat inconsistent. No plans to invest further in fixing it just yet.
This is probably a bug with VSCode's JS xterm module, not a node-pty or winpty bug. I placed these two lines in an untitled editor window: I then set the environment variable , started VSCode, and copy-and-pasted the two lines above into VSCode's integrated terminal. This appeared in the winpty trace: The clipboard has CRLF-delimited lines, because we're on Windows. However, in the VT/100 input format, CR means Return, and LF means Ctrl-Return. Something (probably the JS xterm) is copying the clipboard contents into the pty, and that something should normalize LF and CRLF into CR. I described this bug in detail the last time I saw it:
thanks! This is likely the culprit then which replaces all end of line chars with on Windows:
Yeah, I think your change will fix the issue. The function looks like it might also need a change. Maybe something like this?
FYI I think you may have run into these issues before? It would be a good idea to test these changes in in tomorrow's Insiders build.
I've certainly experienced aspects of this issue from the Python extension when running selections of code in the terminal.
I was unable to reproduce the problem anyway, so have no way of testing this. But thanks for letting me know :-)

} export class TerminalInstance implements ITerminalInstance { <del> private static readonly EOL_REGEX = /r?n/g; </del> <ins> private static readonly WINDOWS_EOL_REGEX = /r?n/g; </ins> private static _terminalProcessFactory: ITerminalProcessFactory = new StandardTerminalProcessFactory(); private static _lastKnownDimensions: Dimension = null;


Question:
VSCode Version: Code - Insiders 1.11.0-insider (, 2017-03-17T08:14:15.805Z) OS Version: Windows_NT ia32 10.0. Extensions: ; Steps to Reproduce: a terminal and run "bash" with a text file containing some lines of text ctrl+v (or right-click) to paste some lines of text What's expected: The text should be appended before the cursor, and the existing text should be there after the cursor. What happens: Existing text disappears, and it seems some extra newlines are when pasting text. Note: there is no such problem when doing the exact same steps with This happens on insider builds, no idea if it happens with standard builds as well.
More information. Here is what happens when I try to paste this text function startagent { echo "Initialising new SSH agent..." /usr/bin/ssh-agent | sed 's/^echo/#echo/' "${SSHENV}" echo succeeded chmod 600 "${SSHENV}" . "${SSHENV}" /dev/null /usr/bin/ssh-add; } In the middle of a file containing this text: existing file with some text Here is what happens with (that's what expected: text is pasted in between existing text): ! Here is what happens with VSCode: text is pasted with extra newlines plus existing text appears in the middle of the pasted text !
Any update on this bug ?
Thanks for the ping. I've validated it's definitely an upstream issue. I tried to fix it a couple of days ago but didn't get anywhere. I'd guess it's related to node-pty or winpty as different shells appeared to handle it differently. It also seemed somewhat inconsistent. No plans to invest further in fixing it just yet.
This is probably a bug with VSCode's JS xterm module, not a node-pty or winpty bug. I placed these two lines in an untitled editor window: I then set the environment variable , started VSCode, and copy-and-pasted the two lines above into VSCode's integrated terminal. This appeared in the winpty trace: The clipboard has CRLF-delimited lines, because we're on Windows. However, in the VT/100 input format, CR means Return, and LF means Ctrl-Return. Something (probably the JS xterm) is copying the clipboard contents into the pty, and that something should normalize LF and CRLF into CR. I described this bug in detail the last time I saw it:
thanks! This is likely the culprit then which replaces all end of line chars with on Windows:
Yeah, I think your change will fix the issue. The function looks like it might also need a change. Maybe something like this?
FYI I think you may have run into these issues before? It would be a good idea to test these changes in in tomorrow's Insiders build.
I've certainly experienced aspects of this issue from the Python extension when running selections of code in the terminal.
I was unable to reproduce the problem anyway, so have no way of testing this. But thanks for letting me know :-)

} public sendText(text: string, addNewLine: boolean): void { <del> if (addNewLine && text.substr(text.length - os.EOL.length) !== os.EOL) { text += os.EOL; </del> <ins> text = this._sanitizeInput(text); if (addNewLine && text.substr(text.length - 1) !== 'r') { text += 'r'; </ins> } this._process.send({ event: 'input',


Question:
VSCode Version: Code - Insiders 1.11.0-insider (, 2017-03-17T08:14:15.805Z) OS Version: Windows_NT ia32 10.0. Extensions: ; Steps to Reproduce: a terminal and run "bash" with a text file containing some lines of text ctrl+v (or right-click) to paste some lines of text What's expected: The text should be appended before the cursor, and the existing text should be there after the cursor. What happens: Existing text disappears, and it seems some extra newlines are when pasting text. Note: there is no such problem when doing the exact same steps with This happens on insider builds, no idea if it happens with standard builds as well.
More information. Here is what happens when I try to paste this text function startagent { echo "Initialising new SSH agent..." /usr/bin/ssh-agent | sed 's/^echo/#echo/' "${SSHENV}" echo succeeded chmod 600 "${SSHENV}" . "${SSHENV}" /dev/null /usr/bin/ssh-add; } In the middle of a file containing this text: existing file with some text Here is what happens with (that's what expected: text is pasted in between existing text): ! Here is what happens with VSCode: text is pasted with extra newlines plus existing text appears in the middle of the pasted text !
Any update on this bug ?
Thanks for the ping. I've validated it's definitely an upstream issue. I tried to fix it a couple of days ago but didn't get anywhere. I'd guess it's related to node-pty or winpty as different shells appeared to handle it differently. It also seemed somewhat inconsistent. No plans to invest further in fixing it just yet.
This is probably a bug with VSCode's JS xterm module, not a node-pty or winpty bug. I placed these two lines in an untitled editor window: I then set the environment variable , started VSCode, and copy-and-pasted the two lines above into VSCode's integrated terminal. This appeared in the winpty trace: The clipboard has CRLF-delimited lines, because we're on Windows. However, in the VT/100 input format, CR means Return, and LF means Ctrl-Return. Something (probably the JS xterm) is copying the clipboard contents into the pty, and that something should normalize LF and CRLF into CR. I described this bug in detail the last time I saw it:
thanks! This is likely the culprit then which replaces all end of line chars with on Windows:
Yeah, I think your change will fix the issue. The function looks like it might also need a change. Maybe something like this?
FYI I think you may have run into these issues before? It would be a good idea to test these changes in in tomorrow's Insiders build.
I've certainly experienced aspects of this issue from the Python extension when running selections of code in the terminal.
I was unable to reproduce the problem anyway, so have no way of testing this. But thanks for letting me know :-)

} private _sanitizeInput(data: any) { <del> return typeof data === 'string' ? data.replace(TerminalInstance.EOL_REGEX, os.EOL) : data; </del> <ins> return typeof data === 'string' ? data.replace(TerminalInstance.WINDOWS_EOL_REGEX, 'r') : data; </ins> } protected _getCwd(shell: IShellLaunchConfig, workspace: IWorkspace): string {


Question:
Chrome-debug supports .js files with query parameters (). But if I load one with "Open loaded scripts", the query parameter is stripped. This happens here: since fsPath doesn't include the query parameter. Any idea how to make this work? I don't think URI is expecting to have a URL with another scheme.
That normalize code should only be executed if the source could not be found - otherwise should not be and the should be passed to the adapter. Do you know why is that? As for the call - I am not married to it and we can change it to whatever uri massaging techinique would work for you and not break the existing behavior. If we change this I would prefer to be in debt week -april
It tries to get the source from , but it looks like that is only populated when it breaks in there, right? Plus it's a different format, the script from the quickopen starts with but the ones in don't.
I don't know about replacing , would do it if that isn't too hacky.
Yes, is only populated once there is a call stack that contains that source - so if it breaks. Yeah that feels like a total hack. Why don't you experiment with different solutions and create a PR where we can comment and try out different approaches if needed?
This regressed from adding back the in DebugContentProvider.getTextContent. is that needed?
Also,
I think opening the file by putting its url into a uri is very fragile, to say the least. I have listed some problems I've noticed while implementing a Loaded Scripts Explorer for the Firefox debug adapter in . My suggestion would be to add the ability to open files using the numerical that the debug adapter assigned to them or using the object that is used for identifying the file in the messages between VS Code and the DA. Whatever solution you adopt, keep in mind that VS Code should be able to determine that the file opened by clicking on a stackframe and the file opened by clicking in the Loaded Scripts Explorer are one and the same - otherwise setting breakpoints in a file opened through the Loaded Scripts Explorer will become problematic.
I've addressed this issue by making sure that the flow -uri -preserves the data so that the initial and resulting objects are identical. The "path" attribute of the source object can contain anything, e.g. a file system path or a full URL. So if a Uri is constructed in the following way: the debugContentProvider inside VS Code will retrieve the content by sending a "sourceRequest" with a "Source" argument to the debug adapter identified by the debug session.
Verify that Rob's Chrome-debug case from above works.
It is escaping the query parameter, but works anyway using the new loadedSources API, because then we can rely on sourceReference instead of a string path.
I have also seen this (with the Firefox debug adapter) and couldn't find any user-visibile ill effects. In particular, the source url is displayed correctly in the tab opened from the Loaded Scripts Explorer (i.e. the query parameter is unescaped there and other escaped characters in the url remain escaped).
Added "Verified" label since both comments from above confirm that this works correctly now.
It does rely on me updating chrome-debug, in case anybody else tries this. I'll do that this week.

*--------------------------------------------------------------------------------------------*/ import uri from 'vs/base/common/uri'; <del> import * as paths from 'vs/base/common/paths'; </del> import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { guessMimeTypes, MIME_TEXT } from 'vs/base/common/mime';


Question:
Chrome-debug supports .js files with query parameters (). But if I load one with "Open loaded scripts", the query parameter is stripped. This happens here: since fsPath doesn't include the query parameter. Any idea how to make this work? I don't think URI is expecting to have a URL with another scheme.
That normalize code should only be executed if the source could not be found - otherwise should not be and the should be passed to the adapter. Do you know why is that? As for the call - I am not married to it and we can change it to whatever uri massaging techinique would work for you and not break the existing behavior. If we change this I would prefer to be in debt week -april
It tries to get the source from , but it looks like that is only populated when it breaks in there, right? Plus it's a different format, the script from the quickopen starts with but the ones in don't.
I don't know about replacing , would do it if that isn't too hacky.
Yes, is only populated once there is a call stack that contains that source - so if it breaks. Yeah that feels like a total hack. Why don't you experiment with different solutions and create a PR where we can comment and try out different approaches if needed?
This regressed from adding back the in DebugContentProvider.getTextContent. is that needed?
Also,
I think opening the file by putting its url into a uri is very fragile, to say the least. I have listed some problems I've noticed while implementing a Loaded Scripts Explorer for the Firefox debug adapter in . My suggestion would be to add the ability to open files using the numerical that the debug adapter assigned to them or using the object that is used for identifying the file in the messages between VS Code and the DA. Whatever solution you adopt, keep in mind that VS Code should be able to determine that the file opened by clicking on a stackframe and the file opened by clicking in the Loaded Scripts Explorer are one and the same - otherwise setting breakpoints in a file opened through the Loaded Scripts Explorer will become problematic.
I've addressed this issue by making sure that the flow -uri -preserves the data so that the initial and resulting objects are identical. The "path" attribute of the source object can contain anything, e.g. a file system path or a full URL. So if a Uri is constructed in the following way: the debugContentProvider inside VS Code will retrieve the content by sending a "sourceRequest" with a "Source" argument to the debug adapter identified by the debug session.
Verify that Rob's Chrome-debug case from above works.
It is escaping the query parameter, but works anyway using the new loadedSources API, because then we can rely on sourceReference instead of a string path.
I have also seen this (with the Firefox debug adapter) and couldn't find any user-visibile ill effects. In particular, the source url is displayed correctly in the tab opened from the Loaded Scripts Explorer (i.e. the query parameter is unescaped there and other escaped characters in the url remain escaped).
Added "Verified" label since both comments from above confirm that this works correctly now.
It does rely on me updating chrome-debug, in case anybody else tries this. I'll do that this week.

return TPromise.wrapError(localize('unable', "Unable to resolve the resource without a debug session")); } const source = process.sources.get(resource.toString()); <del> const rawSource = source ? source.raw : { path: paths.normalize(resource.fsPath, true) }; </del> <ins> let rawSource: DebugProtocol.Source; if (source) { rawSource = source.raw; } else { // Remove debug: scheme rawSource = { path: resource.with({ scheme: '' }).toString(true) }; } </ins> return process.session.source({ sourceReference: source ? source.reference : undefined, source: rawSource }).then(response => { const mime = response.body.mimeType || guessMimeTypes(resource.toString())[0];


Question:
Variable substitutions that are available for (see ) do not include currently selected text. I am looking for something similar to $(CurText) that is available in Visual Studio Arguments for External Tools (see ). Please add a variable ${curtext} which would be replaced with the currently selected text in the editor window. If no selection is available, it could use the current line at cursor position.
Nice idea, but I think it's too late for implement that in the current milestone...
Fixed by in
Verifiers: what happens if all text in a 300 MB file is selected...
good point. Maybe we should put a limit on this. Or only to copy the howl line at most (even though the line could also be 300mb I am fine with that) thoughts?
Selecting lots of text, at some point I get . If there's a predictable limit where this will fail, we should just cut the string off there. Unless only sending part of the text could be dangerous or unexpected for the user. In any case I think that sending multiple lines of text could be useful.
there is not a predictable limit since the variables are used in different scenarios. If somebody has an idea for a limit I am open to PRs

return ''; } <ins> private get selectedText(): string { const activeEditor = this.editorService.getActiveEditor(); if (activeEditor) { const editorControl = (<ICodeEditor>activeEditor.getControl()); if (editorControl) { const editorModel = editorControl.getModel(); const editorSelection = editorControl.getSelection(); if (editorModel && editorSelection) { return editorModel.getValueInRange(editorSelection); } } } return ''; } </ins> private getFilePath(): string { let input = this.editorService.getActiveEditorInput(); if (input instanceof DiffEditorInput) {


Question:
Variable substitutions that are available for (see ) do not include currently selected text. I am looking for something similar to $(CurText) that is available in Visual Studio Arguments for External Tools (see ). Please add a variable ${curtext} which would be replaced with the currently selected text in the editor window. If no selection is available, it could use the current line at cursor position.
Nice idea, but I think it's too late for implement that in the current milestone...
Fixed by in
Verifiers: what happens if all text in a 300 MB file is selected...
good point. Maybe we should put a limit on this. Or only to copy the howl line at most (even though the line could also be 300mb I am fine with that) thoughts?
Selecting lots of text, at some point I get . If there's a predictable limit where this will fail, we should just cut the string off there. Unless only sending part of the text could be dangerous or unexpected for the user. In any case I think that sending multiple lines of text could be useful.
there is not a predictable limit since the variables are used in different scenarios. If somebody has an idea for a limit I am open to PRs

assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); }); <ins> test('current selected text', () => { assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`); }); </ins> test('substitute many', () => { if (platform.isWindows) { assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), 'VSCodeworkspaceLocation - VSCodeworkspaceLocation');