Route open providers by request mode
This commit is contained in:
parent
f87f8235bd
commit
fb68c54409
|
|
@ -97,8 +97,8 @@ Frontend bundles are mounted with a plugin-scoped API created by
|
||||||
a concrete editor plugin.
|
a concrete editor plugin.
|
||||||
|
|
||||||
Editor/viewer plugins contribute providers with `contributes.openProviders`.
|
Editor/viewer plugins contribute providers with `contributes.openProviders`.
|
||||||
Workbench selects by resource kind, extension/mime, context (`generic-text`,
|
Workbench selects by resource kind, request mode, extension/mime, context
|
||||||
`generic-markdown`, `notes-markdown`), user preference, priority, then
|
(`generic-text`, `generic-markdown`, `notes-markdown`), user preference, priority, then
|
||||||
deterministic `pluginId/providerId` tie-break. If nothing matches, Workbench
|
deterministic `pluginId/providerId` tie-break. If nothing matches, Workbench
|
||||||
shows `no-provider` fallback instead of a core editor.
|
shows `no-provider` fallback instead of a core editor.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,8 @@ the Workbench helper.
|
||||||
{
|
{
|
||||||
"kind": "vault-file",
|
"kind": "vault-file",
|
||||||
"extensions": [".md", ".markdown"],
|
"extensions": [".md", ".markdown"],
|
||||||
"contexts": ["generic-markdown", "notes-markdown"]
|
"contexts": ["generic-markdown", "notes-markdown"],
|
||||||
|
"modes": ["view"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "vault-file",
|
"kind": "vault-file",
|
||||||
|
|
@ -333,7 +334,7 @@ the Workbench helper.
|
||||||
```
|
```
|
||||||
|
|
||||||
Selection uses enabled loaded/degraded provider plugins, resource kind,
|
Selection uses enabled loaded/degraded provider plugins, resource kind,
|
||||||
extension/mime, context, user preference, priority, then deterministic
|
request mode, extension/mime, context, user preference, priority, then deterministic
|
||||||
`pluginId/providerId` fallback. If nothing matches, Workbench returns
|
`pluginId/providerId` fallback. If nothing matches, Workbench returns
|
||||||
`status: "no-provider"` and shows the fallback view instead of a core editor.
|
`status: "no-provider"` and shows the fallback view instead of a core editor.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -339,8 +339,10 @@
|
||||||
function providerSupports(provider, request) {
|
function providerSupports(provider, request) {
|
||||||
var ext = requestExtension(request);
|
var ext = requestExtension(request);
|
||||||
var contextName = requestContextName(request);
|
var contextName = requestContextName(request);
|
||||||
|
var mode = String((request && request.mode) || 'view').toLowerCase();
|
||||||
return (provider.supports || []).some(function (support) {
|
return (provider.supports || []).some(function (support) {
|
||||||
if (support.kind && support.kind !== request.kind) return false;
|
if (support.kind && support.kind !== request.kind) return false;
|
||||||
|
if (support.modes && support.modes.length && support.modes.map(function (m) { return String(m).toLowerCase(); }).indexOf(mode) === -1) return false;
|
||||||
if (support.extensions && support.extensions.length && support.extensions.map(function (e) { return String(e).toLowerCase(); }).indexOf(ext) === -1) return false;
|
if (support.extensions && support.extensions.length && support.extensions.map(function (e) { return String(e).toLowerCase(); }).indexOf(ext) === -1) return false;
|
||||||
if (support.contexts && support.contexts.length && support.contexts.indexOf(contextName) === -1) return false;
|
if (support.contexts && support.contexts.length && support.contexts.indexOf(contextName) === -1) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ export namespace api {
|
||||||
mime?: string[];
|
mime?: string[];
|
||||||
extensions?: string[];
|
extensions?: string[];
|
||||||
contexts?: string[];
|
contexts?: string[];
|
||||||
|
modes?: string[];
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new FlatOpenProviderSupport(source);
|
return new FlatOpenProviderSupport(source);
|
||||||
|
|
@ -36,6 +37,7 @@ export namespace api {
|
||||||
this.mime = source["mime"];
|
this.mime = source["mime"];
|
||||||
this.extensions = source["extensions"];
|
this.extensions = source["extensions"];
|
||||||
this.contexts = source["contexts"];
|
this.contexts = source["contexts"];
|
||||||
|
this.modes = source["modes"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FlatOpenProvider {
|
export class FlatOpenProvider {
|
||||||
|
|
@ -534,6 +536,7 @@ export namespace plugin {
|
||||||
mime?: string[];
|
mime?: string[];
|
||||||
extensions?: string[];
|
extensions?: string[];
|
||||||
contexts?: string[];
|
contexts?: string[];
|
||||||
|
modes?: string[];
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new OpenProviderSupport(source);
|
return new OpenProviderSupport(source);
|
||||||
|
|
@ -545,6 +548,7 @@ export namespace plugin {
|
||||||
this.mime = source["mime"];
|
this.mime = source["mime"];
|
||||||
this.extensions = source["extensions"];
|
this.extensions = source["extensions"];
|
||||||
this.contexts = source["contexts"];
|
this.contexts = source["contexts"];
|
||||||
|
this.modes = source["modes"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class ContributionOpenProvider {
|
export class ContributionOpenProvider {
|
||||||
|
|
@ -1159,4 +1163,3 @@ export namespace workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,7 @@ type FlatOpenProviderSupport struct {
|
||||||
Mime []string `json:"mime,omitempty"`
|
Mime []string `json:"mime,omitempty"`
|
||||||
Extensions []string `json:"extensions,omitempty"`
|
Extensions []string `json:"extensions,omitempty"`
|
||||||
Contexts []string `json:"contexts,omitempty"`
|
Contexts []string `json:"contexts,omitempty"`
|
||||||
|
Modes []string `json:"modes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FlatOpenProvider struct {
|
type FlatOpenProvider struct {
|
||||||
|
|
@ -316,7 +317,7 @@ func buildContributionSummary(r *contribution.Registry) ContributionSummary {
|
||||||
for i, v := range regOpenProviders {
|
for i, v := range regOpenProviders {
|
||||||
supports := make([]FlatOpenProviderSupport, len(v.Item.Supports))
|
supports := make([]FlatOpenProviderSupport, len(v.Item.Supports))
|
||||||
for j, s := range v.Item.Supports {
|
for j, s := range v.Item.Supports {
|
||||||
supports[j] = FlatOpenProviderSupport{Kind: s.Kind, Mime: s.Mime, Extensions: s.Extensions, Contexts: s.Contexts}
|
supports[j] = FlatOpenProviderSupport{Kind: s.Kind, Mime: s.Mime, Extensions: s.Extensions, Contexts: s.Contexts, Modes: s.Modes}
|
||||||
}
|
}
|
||||||
openProviders[i] = FlatOpenProvider{
|
openProviders[i] = FlatOpenProvider{
|
||||||
PluginID: v.PluginID,
|
PluginID: v.PluginID,
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ type OpenProviderSupport struct {
|
||||||
Mime []string `json:"mime,omitempty"`
|
Mime []string `json:"mime,omitempty"`
|
||||||
Extensions []string `json:"extensions,omitempty"`
|
Extensions []string `json:"extensions,omitempty"`
|
||||||
Contexts []string `json:"contexts,omitempty"`
|
Contexts []string `json:"contexts,omitempty"`
|
||||||
|
Modes []string `json:"modes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContributionOpenProvider represents an editor/viewer provider contribution.
|
// ContributionOpenProvider represents an editor/viewer provider contribution.
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,9 @@ func providerMatches(request OpenResourceRequest, provider plugin.ContributionOp
|
||||||
if support.Kind != request.Kind {
|
if support.Kind != request.Kind {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if !supportMatchesMode(request, support) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !supportMatchesExtensionOrMime(request, support) {
|
if !supportMatchesExtensionOrMime(request, support) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +182,19 @@ func providerMatches(request OpenResourceRequest, provider plugin.ContributionOp
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func supportMatchesMode(request OpenResourceRequest, support plugin.OpenProviderSupport) bool {
|
||||||
|
if len(support.Modes) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
mode := strings.ToLower(request.Mode)
|
||||||
|
for _, supported := range support.Modes {
|
||||||
|
if strings.ToLower(supported) == mode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func supportMatchesExtensionOrMime(request OpenResourceRequest, support plugin.OpenProviderSupport) bool {
|
func supportMatchesExtensionOrMime(request OpenResourceRequest, support plugin.OpenProviderSupport) bool {
|
||||||
hasExtensionRules := len(support.Extensions) > 0
|
hasExtensionRules := len(support.Extensions) > 0
|
||||||
hasMimeRules := len(support.Mime) > 0
|
hasMimeRules := len(support.Mime) > 0
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,47 @@ func TestSelectProviderFallsBackByPriorityThenID(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelectProviderHonorsSupportModes(t *testing.T) {
|
||||||
|
r := NewRouter(Preferences{})
|
||||||
|
providers := []contribution.ContributionOpenProvider{
|
||||||
|
provider("preview.plugin", "markdown.preview", 100, "MarkdownPreview", plugin.OpenProviderSupport{
|
||||||
|
Kind: "vault-file",
|
||||||
|
Extensions: []string{".md"},
|
||||||
|
Contexts: []string{ContextGenericMarkdown},
|
||||||
|
Modes: []string{"view"},
|
||||||
|
}),
|
||||||
|
provider("editor.plugin", "markdown.editor", 50, "MarkdownEditor", plugin.OpenProviderSupport{
|
||||||
|
Kind: "vault-file",
|
||||||
|
Extensions: []string{".md"},
|
||||||
|
Contexts: []string{ContextGenericMarkdown},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
viewProvider, err := r.SelectProvider(OpenResourceRequest{
|
||||||
|
Kind: "vault-file",
|
||||||
|
Path: "Docs/readme.md",
|
||||||
|
Mode: "view",
|
||||||
|
}, providers)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SelectProvider(view): %v", err)
|
||||||
|
}
|
||||||
|
if viewProvider.Item.ID != "markdown.preview" {
|
||||||
|
t.Fatalf("view provider = %q, want markdown.preview", viewProvider.Item.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
editProvider, err := r.SelectProvider(OpenResourceRequest{
|
||||||
|
Kind: "vault-file",
|
||||||
|
Path: "Docs/readme.md",
|
||||||
|
Mode: "edit",
|
||||||
|
}, providers)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SelectProvider(edit): %v", err)
|
||||||
|
}
|
||||||
|
if editProvider.Item.ID != "markdown.editor" {
|
||||||
|
t.Fatalf("edit provider = %q, want markdown.editor", editProvider.Item.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSelectProviderTieBreaksByPluginIDThenProviderID(t *testing.T) {
|
func TestSelectProviderTieBreaksByPluginIDThenProviderID(t *testing.T) {
|
||||||
r := NewRouter(Preferences{})
|
r := NewRouter(Preferences{})
|
||||||
providers := []contribution.ContributionOpenProvider{
|
providers := []contribution.ContributionOpenProvider{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue