Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,993 changes: 1,993 additions & 0 deletions MONACO_INPUT_STEP_BY_STEP_TUTORIAL.md

Large diffs are not rendered by default.

971 changes: 971 additions & 0 deletions MONACO_INPUT_TUTORIAL.md

Large diffs are not rendered by default.

4,126 changes: 3,982 additions & 144 deletions package-lock.json

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions src/vs/workbench/contrib/monacoInput/browser/media/monacoInput.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.monaco-input-toolbar {
padding: 8px;
border-bottom: 1px solid var(--vscode-input-border);
background: var(--vscode-editor-background);
}

.monaco-input-toolbar .monaco-button {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: 1px solid var(--vscode-button-border, transparent);
padding: 6px 12px;
border-radius: 3px;
font-size: 13px;
cursor: pointer;
}

.monaco-input-toolbar .monaco-button:hover {
background: var(--vscode-button-hoverBackground);
}

.monaco-input-toolbar .monaco-button.primary {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
}

.monaco-input-toolbar .monaco-button.primary:hover {
background: var(--vscode-button-hoverBackground);
}

.monaco-input-container {
flex: 1;
min-height: 300px;
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
margin: 8px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import './media/monacoInput.css';
import * as nls from '../../../../nls.js';
import { Registry } from '../../../../platform/registry/common/platform.js';
import { Extensions as ViewExtensions, IViewsRegistry } from '../../../common/views.js';
import { MonacoInputViewPane } from './monacoInputView.js';
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js';
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, ViewContainerLocation } from '../../../common/views.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { IViewsService } from '../../../services/views/common/viewsService.js';

// Register the view container for auxiliary bar
const VIEW_CONTAINER_ID = 'workbench.view.monacoInputContainer';

const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);

// Register view container in auxiliary bar (secondary sidebar)
const viewContainer = viewContainerRegistry.registerViewContainer({
id: VIEW_CONTAINER_ID,
title: { value: nls.localize('monacoInputContainer', "Monaco Input"), original: 'Monaco Input' },
ctorDescriptor: new SyncDescriptor(
ViewPaneContainer,
[VIEW_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true }]
),
hideIfEmpty: true,
icon: Codicon.edit,
order: 5
}, ViewContainerLocation.AuxiliaryBar);

// Register the view in the container
viewsRegistry.registerViews([{
id: MonacoInputViewPane.ID,
name: { value: MonacoInputViewPane.TITLE, original: 'Monaco Input' },
ctorDescriptor: new SyncDescriptor(MonacoInputViewPane),
canToggleVisibility: true,
canMoveView: true,
containerIcon: Codicon.edit,
order: 100,
when: undefined
}], viewContainer);

// Register button commands
registerAction2(class ClearMonacoInputAction extends Action2 {
constructor() {
super({
id: 'monacoInput.clear',
title: { value: nls.localize('monacoInput.clear', "Clear Input"), original: 'Clear Input' },
icon: Codicon.clearAll,
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.equals('view', MonacoInputViewPane.ID),
group: 'navigation',
order: 1
}
});
}

async run(accessor: ServicesAccessor): Promise<void> {
const viewsService = accessor.get(IViewsService);
const view = viewsService.getActiveViewWithId(MonacoInputViewPane.ID) as MonacoInputViewPane | null;

if (view) {
view.clearContent();
}
}
});

registerAction2(class SaveMonacoInputAction extends Action2 {
constructor() {
super({
id: 'monacoInput.save',
title: { value: nls.localize('monacoInput.save', "Save Content"), original: 'Save Content' },
icon: Codicon.save,
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.equals('view', MonacoInputViewPane.ID),
group: 'navigation',
order: 2
}
});
}

async run(accessor: ServicesAccessor): Promise<void> {
const viewsService = accessor.get(IViewsService);
const view = viewsService.getActiveViewWithId(MonacoInputViewPane.ID) as MonacoInputViewPane | null;

if (view) {
const content = view.getValue();
// Here you would implement save logic
console.log('Saving content:', content);
}
}
});
Comment on lines +77 to +102
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Save action currently only logs to the developer console. In product code this should either implement actual save behavior (e.g. save to a user-chosen file / workspace file via IFileService) or be removed until implemented.

Suggested change
registerAction2(class SaveMonacoInputAction extends Action2 {
constructor() {
super({
id: 'monacoInput.save',
title: { value: nls.localize('monacoInput.save', "Save Content"), original: 'Save Content' },
icon: Codicon.save,
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.equals('view', MonacoInputViewPane.ID),
group: 'navigation',
order: 2
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const viewsService = accessor.get(IViewsService);
const view = viewsService.getActiveViewWithId(MonacoInputViewPane.ID) as MonacoInputViewPane | null;
if (view) {
const content = view.getValue();
// Here you would implement save logic
console.log('Saving content:', content);
}
}
});

Copilot uses AI. Check for mistakes.
158 changes: 158 additions & 0 deletions src/vs/workbench/contrib/monacoInput/browser/monacoInputView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import * as dom from '../../../../base/browser/dom.js';
import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
Comment on lines +1 to +3
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new TypeScript source file is missing the standard Microsoft copyright header block that other VS Code source files include. Please add the repository’s standard header at the top of the file.

Copilot uses AI. Check for mistakes.
import { IEditorOptions } from '../../../../editor/common/config/editorOptions.js';
import { ITextModel } from '../../../../editor/common/model.js';
import { ILanguageService } from '../../../../editor/common/languages/language.js';
import { IModelService } from '../../../../editor/common/services/model.js';
import * as nls from '../../../../nls.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { IViewPaneOptions, ViewPane } from '../../../browser/parts/views/viewPane.js';
import { IViewDescriptorService } from '../../../common/views.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
import { URI } from '../../../../base/common/uri.js';
import { ICommandService } from '../../../../platform/commands/common/commands.js';

export class MonacoInputViewPane extends ViewPane {
static readonly ID = 'workbench.views.monacoInput';
static readonly TITLE = nls.localize('monacoInput', "Monaco Input");

private _editor: ICodeEditor | undefined;
private _editorContainer: HTMLElement | undefined;
private _textModel: ITextModel | undefined;

constructor(
options: IViewPaneOptions,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService,
@IContextKeyService protected override readonly contextKeyService: IContextKeyService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IInstantiationService protected override readonly instantiationService: IInstantiationService,
@IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
@IHoverService hoverService: IHoverService,
@IModelService private readonly modelService: IModelService,
@ILanguageService private readonly languageService: ILanguageService,
@ICommandService private readonly commandService: ICommandService,
) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);
}

protected override renderBody(container: HTMLElement): void {
super.renderBody(container);

// Create toolbar with run button
const toolbar = dom.$('.monaco-input-toolbar');
const runButton = dom.$('button.monaco-button.primary', {
type: 'button',
title: 'Run Python Code'
});
runButton.textContent = '🐍 Run Python';
Comment on lines +55 to +57
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run button label/title are user-facing strings but are not localized (and include an emoji). Please use nls.localize(...) for user-visible UI strings and follow existing label conventions.

Suggested change
title: 'Run Python Code'
});
runButton.textContent = '🐍 Run Python';
title: nls.localize('monacoInput.runPythonButtonTitle', "Run Python")
});
runButton.textContent = nls.localize('monacoInput.runPythonButtonLabel', "Run Python");

Copilot uses AI. Check for mistakes.
toolbar.appendChild(runButton);

// Create editor container
this._editorContainer = dom.$('.monaco-input-container');

container.appendChild(toolbar);
container.appendChild(this._editorContainer);

this.createEditor();

// Run button click handler
this._register(dom.addDisposableListener(runButton, 'click', () => {
this.runPython();
}));
}

private createEditor(): void {
if (!this._editorContainer) {
return;
}

// Create Python text model
this._textModel = this.modelService.createModel(
'# Type your Python code here\nprint("Hello from Python!")\n',
this.languageService.createById('python'),
URI.from({ scheme: 'inmemory', path: '/monaco-python.py' })
);

// Simple editor options
const editorOptions: IEditorOptions = {
minimap: { enabled: false },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add soon

lineNumbers: 'on',
wordWrap: 'on',
fontSize: 14,
scrollBeyondLastLine: false,
automaticLayout: true
};

// Create editor
this._editor = this.instantiationService.createInstance(
CodeEditorWidget,
this._editorContainer,
editorOptions,
{ isSimpleWidget: false, contributions: [] }
);

this._editor.setModel(this._textModel);
this._register(this._editor);
this._register(this._textModel);
}

private runPython(): void {
const code = this._editor?.getValue() || '';
if (!code.trim()) {
return;
}

// Create a unique temp file name
const tempFileName = `vscode_monaco_${Date.now()}.py`;
const tempFilePath = `/tmp/${tempFileName}`;

// Create terminal and execute the script
this.commandService.executeCommand('workbench.action.terminal.new');

// Hide command completely, only show clean output
setTimeout(() => {
// Clear screen and execute silently
const cleanCommand = `clear; cat > ${tempFilePath} << 'EOF' 2>/dev/null\n${code}\nEOF\necho "🐍 Running Python..."\npython3 ${tempFilePath} 2>&1\nrm ${tempFilePath} 2>/dev/null`;

this.commandService.executeCommand('workbench.action.terminal.sendSequence', {
text: cleanCommand + '\n'
});
}, 150);
Comment on lines +109 to +130
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runPython() builds a shell script by interpolating arbitrary editor content into a heredoc and sends it to the terminal. This is not cross-platform (/tmp, clear, python3) and is vulnerable to heredoc breakouts (e.g. code containing EOF) causing unintended shell execution. Please rework to a safe, OS-agnostic approach (e.g. write via IFileService to a temp location from VS Code services, properly quote paths, and execute Python via a dedicated task/terminal API rather than injecting raw shell).

Copilot uses AI. Check for mistakes.
}


public getValue(): string {
return this._editor?.getValue() || '';
}

public setValue(value: string): void {
this._editor?.setValue(value);
}

public clearContent(): void {
this._editor?.setValue('# Type your Python code here\nprint("Hello from Python!")\n');
this._editor?.focus();
}

override focus(): void {
super.focus();
this._editor?.focus();
}

override setVisible(visible: boolean): void {
super.setVisible(visible);
if (visible) {
this._editor?.layout();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ type GettingStartedStartEntryContent = BuiltinGettingStartedStartEntry[];
export const startEntries: GettingStartedStartEntryContent = [
{
id: 'welcome.showNewFileEntries',
title: localize('gettingStarted.newFile.title', "New File..."),
title: "ارمي الملف يا علييييييي",
description: localize('gettingStarted.newFile.description', "Open a new untitled text file, notebook, or custom editor."),
icon: Codicon.newFile,
content: {
Expand All @@ -121,7 +121,7 @@ export const startEntries: GettingStartedStartEntryContent = [
},
{
id: 'topLevelOpenMac',
title: localize('gettingStarted.openMac.title', "Open..."),
title: "هات المجلد يا عبدوووو",
description: localize('gettingStarted.openMac.description', "Open a file or folder to start working"),
icon: Codicon.folderOpened,
when: '!isWeb && isMac',
Expand Down Expand Up @@ -247,7 +247,9 @@ function createCopilotSetupStep(id: string, button: string, when: string, includ
export const walkthroughs: GettingStartedWalkthroughContent = [
{
id: 'Setup',
title: localize('gettingStarted.setup.title', "Get started with VS Code"),
// title: localize('gettingStarted.setup.title', "Get started with VS Code"),
title: "Get Started with AbuCode",

description: localize('gettingStarted.setup.description', "Customize your editor, learn the basics, and start coding"),
isFeatured: true,
icon: setupIcon,
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/workbench.common.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ import './contrib/chat/browser/chat.contribution.js';
import './contrib/inlineChat/browser/inlineChat.contribution.js';
import './contrib/mcp/browser/mcp.contribution.js';

// Monaco Input
import './contrib/monacoInput/browser/monacoInput.contribution.js';

// Interactive
import './contrib/interactive/browser/interactive.contribution.js';
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing these new contributions from workbench.common.main.ts wires them into every VS Code build by default. Given the experimental nature (terminal execution + external network calls), these should be behind an explicit feature flag / configuration and not enabled unconditionally in the core workbench entrypoint.

Suggested change
import './contrib/interactive/browser/interactive.contribution.js';
if (globalThis.vscodeExperimentalInteractiveContribution === true) {
void import('./contrib/interactive/browser/interactive.contribution.js');
}

Copilot uses AI. Check for mistakes.

Expand Down