microsoft / microsoft/vscode

Allow custom editors and editor defaults to target language IDs

Open
#335,704 0 comments 0 reactions 0 assignees View on GitHub
custom-editors feature-request
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

## Summary

Allow custom editors to target language IDs in addition to filename globs, and allow users to configure a language-wide default editor from **Reopen Editor With...** and the editor-type dropdown in breadcrumbs.

Today, `contributes.customEditors[].selector` only supports `filenamePattern`. This forces custom editors to duplicate every filename association of a language and means they do not automatically apply to extensions or filename patterns added through `files.associations`.

For example, Markdown recognizes many extensions and filename patterns, while the built-in Markdown custom editors currently have to target specific globs such as `*.md`. A file associated with the `markdown` language under a different extension does not offer those custom editors.

Related prior discussion: #129553 established that associating a language with a custom editor is not currently possible, but it was closed as a question and does not track the feature or language-wide default behavior. The selector shape was originally designed for future expansion similar to document selectors: #94384.

## Proposed custom editor selector

Support a `language` field in custom editor selectors:

```json
{
"contributes": {
"customEditors": [
{
"viewType": "example.markdownEditor",
"displayName": "Markdown Editor",
"priority": "option",
"selector": [
{
"language": "markdown"
}
]
}
]
}
}
```

Existing `filenamePattern` selectors must remain supported. If both fields are specified in one selector, they should be combined as an AND condition; entries in the selector array remain OR conditions. This would allow selectors such as:

```json
"selector": [
{
"language": "markdown",
"filenamePattern": "docs/**"
}
]
```

Language matching should use the resource's effective language ID:

- On initial open, infer it from registered language contributions and `files.associations`.
- If a text model already exists, use its current language ID.
- Re-evaluate editor availability when the model language or language associations change.

This avoids requiring a custom editor to copy a language's extension, filename, and filename-pattern lists.

## Reopen With and breadcrumbs

When a language selector matches, the custom editor should appear consistently in:

- **Reopen Editor With...**
- the editor-type dropdown shown in breadcrumbs
- the **Reopen Editor With** submenu in the editor title overflow menu
- normal editor resolution when the contribution has default priority
- diff editor resolution when the contribution opts into diffs

All these surfaces should use the same resolver match result so they cannot disagree about editor availability.

## Language-wide default editor associations

When an editor is available because of a language selector, choosing **Set Default** should create a language-wide default instead of deriving a glob from the current file's extension.

For example, the UI could show:

> Set Default for 'Markdown'

A possible settings representation is:

```json
"workbench.editorLanguageAssociations": {
"markdown": "example.markdownEditor"
},
"workbench.diffEditorLanguageAssociations": {
"markdown": "example.markdownEditor"
}
```

The exact storage shape is an implementation detail, but it should support independent normal-editor and diff-editor defaults, matching the existing `workbench.editorAssociations` and `workbench.diffEditorAssociations` behavior.

Suggested precedence:

1. A matching explicit filename-pattern association
2. A matching explicit language association
3. The natural priority of matching editor contributions
4. The default text editor fallback

Diff-specific associations should take precedence over normal-editor associations in diff views.

This preserves precise filename overrides while allowing one default to cover all resources associated with a language, including custom extensions configured through `files.associations`.

## Expected behavior

Given:

```json
"files.associations": {
"*.notes": "markdown"
},
"workbench.editorLanguageAssociations": {
"markdown": "example.markdownEditor"
}
```

and a custom editor with `{ "language": "markdown" }`:

1. Opening `README.md` uses `example.markdownEditor`.
2. Opening `meeting.notes` also uses `example.markdownEditor`.
3. **Reopen Editor With...** and the breadcrumbs editor-type dropdown offer the same editor choices for both files.
4. A more-specific filename association can override the language-wide default for either file.
5. Existing extensions using only `filenamePattern` continue to behave unchanged.

Contributor guide

Open the contributing guide

Research direction

Start by tracing custom editor selector resolution and the editor association handling behind Reopen Editor With..., breadcrumbs, editor-title overflow, and diff resolution. Compare matching for filenamePattern and effective language IDs, then verify that language-wide normal and diff defaults preserve filename overrides and produce the expected behavior for README.md and a file.associated with markdown.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, vscode
Domain
desktop, developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.