src/vs/editor/contrib/suggest/browser/suggestWidget.ts/SuggestWidget/constructor
class SuggestWidget:	constructor(
		private readonly editor: ICodeEditor,
		@IStorageService private readonly _storageService: IStorageService,
		@IContextKeyService _contextKeyService: IContextKeyService,
		@IThemeService _themeService: IThemeService,
		@IInstantiationService instantiationService: IInstantiationService,
	) {
		this.element = new ResizableHTMLElement();
		this.element.domNode.classList.add('editor-widget', 'suggest-widget');

		this._contentWidget = new SuggestContentWidget(this, editor);
		this._persistedSize = new PersistedWidgetSize(_storageService, 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(() => {
			this._contentWidget.lockPreference();
			state = new ResizeState(this._persistedSize.restore(), this.element.size);
		}));
		this._disposables.add(this.element.onDidResize(e => {

			this._resize(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) {
				// only store width or height value that have changed and also
				// only store changes that are above a certain threshold
				const { itemHeight, defaultSize } = this.getLayoutInfo();
				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 ?? defaultSize.height;
				}
				if (!state.persistWidth || Math.abs(state.currentSize.width - width) <= threshold) {
					width = state.persistedSize?.width ?? defaultSize.width;
				}
				this._persistedSize.store(new dom.Dimension(width, height));
			}

			// reset working state
			this._contentWidget.unlockPreference();
			state = undefined;
		}));

		this._messageElement = dom.append(this.element.domNode, dom.$('.message'));
		this._listElement = dom.append(this.element.domNode, dom.$('.tree'));

		const details = instantiationService.createInstance(SuggestDetailsWidget, this.editor);
		details.onDidClose(this.toggleDetails, this, this._disposables);
		this._details = new SuggestDetailsOverlay(details, this.editor);

		const applyIconStyle = () => this.element.domNode.classList.toggle('no-icons', !this.editor.getOption(EditorOption.suggest).showIcons);
		applyIconStyle();

		const renderer = instantiationService.createInstance(ItemRenderer, this.editor);
		this._disposables.add(renderer);
		this._disposables.add(renderer.onDidToggleDetails(() => this.toggleDetails()));

		this._list = new List('SuggestWidget', this._listElement, {
			getHeight: (_element: CompletionItem): number => this.getLayoutInfo().itemHeight,
			getTemplateId: (_element: CompletionItem): string => 'suggestion'
		}, [renderer], {
			alwaysConsumeMouseWheel: true,
			useShadows: false,
			mouseSupport: false,
			accessibilityProvider: {
				getRole: () => 'option',
				getWidgetAriaLabel: () => nls.localize('suggest', "Suggest"),
				getWidgetRole: () => 'listbox',
				getAriaLabel: (item: CompletionItem) => {

					let label = item.textLabel;
					if (typeof item.completion.label !== 'string') {
						const { detail, description } = item.completion.label;
						if (detail && description) {
							label = nls.localize('label.full', '{0}{1}, {2}', label, detail, description);
						} else if (detail) {
							label = nls.localize('label.detail', '{0}{1}', label, detail);
						} else if (description) {
							label = nls.localize('label.desc', '{0}, {1}', label, description);
						}
					}

					if (!item.isResolved || !this._isDetailsVisible()) {
						return label;
					}

					const { documentation, detail } = item.completion;
					const docs = strings.format(
						'{0}{1}',
						detail || '',
						documentation ? (typeof documentation === 'string' ? documentation : documentation.value) : '');

					return nls.localize('ariaCurrenttSuggestionReadDetails', "{0}, docs: {1}", label, docs);
				},
			}
		});

		this._status = instantiationService.createInstance(SuggestWidgetStatus, this.element.domNode);
		const applyStatusBarStyle = () => this.element.domNode.classList.toggle('with-status-bar', this.editor.getOption(EditorOption.suggest).showStatusBar);
		applyStatusBarStyle();

		this._disposables.add(attachListStyler(this._list, _themeService, {
			listInactiveFocusBackground: editorSuggestWidgetSelectedBackground,
			listInactiveFocusOutline: activeContrastBorder
		}));
		this._disposables.add(_themeService.onDidColorThemeChange(t => this._onThemeChange(t)));
		this._onThemeChange(_themeService.getColorTheme());

		this._disposables.add(this._list.onMouseDown(e => this._onListMouseDownOrTap(e)));
		this._disposables.add(this._list.onTap(e => this._onListMouseDownOrTap(e)));
		this._disposables.add(this._list.onDidChangeSelection(e => this._onListSelection(e)));
		this._disposables.add(this._list.onDidChangeFocus(e => this._onListFocus(e)));
		this._disposables.add(this.editor.onDidChangeCursorSelection(() => this._onCursorSelectionChanged()));
		this._disposables.add(this.editor.onDidChangeConfiguration(e => {
			if (e.hasChanged(EditorOption.suggest)) {
				applyStatusBarStyle();
				applyIconStyle();
			}
		}));

		this._ctxSuggestWidgetVisible = SuggestContext.Visible.bindTo(_contextKeyService);
		this._ctxSuggestWidgetDetailsVisible = SuggestContext.DetailsVisible.bindTo(_contextKeyService);
		this._ctxSuggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(_contextKeyService);


		this._disposables.add(dom.addStandardDisposableListener(this._details.widget.domNode, 'keydown', e => {
			this._onDetailsKeydown.fire(e);
		}));

		this._disposables.add(this.editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e)));
	}