mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
WEB-32238 JSON Schema: dropdown to choose JSON schemas
This commit is contained in:
@@ -84,9 +84,11 @@ public class JsonSchemaMappingsConfigurable extends MasterDetailsComponent imple
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addProjectSchema() {
|
||||
addCreatedMappings(new UserDefinedJsonSchemaConfiguration(createUniqueName(STUB_SCHEMA_NAME),
|
||||
JsonSchemaVersion.SCHEMA_4, "", false, null));
|
||||
public UserDefinedJsonSchemaConfiguration addProjectSchema() {
|
||||
UserDefinedJsonSchemaConfiguration configuration = new UserDefinedJsonSchemaConfiguration(createUniqueName(STUB_SCHEMA_NAME),
|
||||
JsonSchemaVersion.SCHEMA_4, "", false, null);
|
||||
addCreatedMappings(configuration);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
|
||||
@@ -9,22 +9,46 @@ import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import com.intellij.util.xmlb.annotations.XCollection;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaInfo;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
|
||||
@State(name = "JsonSchemaMappingsProjectConfiguration", storages = @Storage("jsonSchemas.xml"))
|
||||
public class JsonSchemaMappingsProjectConfiguration implements PersistentStateComponent<JsonSchemaMappingsProjectConfiguration.MyState> {
|
||||
@NotNull private final Project myProject;
|
||||
public volatile MyState myState = new MyState();
|
||||
|
||||
@Nullable
|
||||
public UserDefinedJsonSchemaConfiguration findMappingBySchemaInfo(JsonSchemaInfo value) {
|
||||
for (UserDefinedJsonSchemaConfiguration configuration : myState.myState.values()) {
|
||||
if (Objects.equals(value.getUrl(), configuration.getRelativePathToSchema())) return configuration;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UserDefinedJsonSchemaConfiguration findMappingForFile(VirtualFile file) {
|
||||
VirtualFile projectBaseDir = myProject.getBaseDir();
|
||||
for (UserDefinedJsonSchemaConfiguration configuration : myState.myState.values()) {
|
||||
for (UserDefinedJsonSchemaConfiguration.Item pattern : configuration.patterns) {
|
||||
if (pattern.pattern || pattern.directory) continue;
|
||||
String path = pattern.path;
|
||||
VirtualFile relativeFile = VfsUtil.findRelativeFile(projectBaseDir, path);
|
||||
if (Objects.equals(relativeFile, file)) {
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JsonSchemaMappingsProjectConfiguration getInstance(@NotNull final Project project) {
|
||||
return ServiceManager.getService(project, JsonSchemaMappingsProjectConfiguration.class);
|
||||
}
|
||||
@@ -51,6 +75,23 @@ public class JsonSchemaMappingsProjectConfiguration implements PersistentStateCo
|
||||
});
|
||||
}
|
||||
|
||||
public void removeConfiguration(UserDefinedJsonSchemaConfiguration configuration) {
|
||||
for (Map.Entry<String, UserDefinedJsonSchemaConfiguration> entry : myState.myState.entrySet()) {
|
||||
if (entry.getValue() == configuration) {
|
||||
myState.myState.remove(entry.getKey());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addConfiguration(UserDefinedJsonSchemaConfiguration configuration) {
|
||||
String name = configuration.getName();
|
||||
while (myState.myState.containsKey(name)) {
|
||||
name += "1";
|
||||
}
|
||||
myState.myState.put(name, configuration);
|
||||
}
|
||||
|
||||
public Map<String, UserDefinedJsonSchemaConfiguration> getStateMap() {
|
||||
return Collections.unmodifiableMap(myState.myState);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,10 @@ public class UserDefinedJsonSchemaConfiguration {
|
||||
myCalculatedPatterns.drop();
|
||||
}
|
||||
|
||||
public void refreshPatterns() {
|
||||
myCalculatedPatterns.drop();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PairProcessor<Project, VirtualFile>> getCalculatedPatterns() {
|
||||
return myCalculatedPatterns.getValue();
|
||||
|
||||
@@ -26,4 +26,12 @@ public interface JsonSchemaFileProvider {
|
||||
default String getThirdPartyApiInformation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default boolean isUserVisible() { return true; }
|
||||
|
||||
@NotNull
|
||||
default String getPresentableName() { return getName(); }
|
||||
|
||||
@Nullable
|
||||
default String getRemoteSource() { return null; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.extension;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaVersion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JsonSchemaInfo {
|
||||
private final JsonSchemaFileProvider myProvider;
|
||||
private final String myUrl;
|
||||
|
||||
public JsonSchemaInfo(@NotNull JsonSchemaFileProvider provider) {
|
||||
myProvider = provider;
|
||||
myUrl = null;
|
||||
}
|
||||
|
||||
public JsonSchemaInfo(@NotNull String url) {
|
||||
myUrl = url;
|
||||
myProvider = null;
|
||||
}
|
||||
|
||||
public JsonSchemaFileProvider getProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myProvider != null ? myProvider.getRemoteSource() : myUrl;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (myProvider != null) {
|
||||
String providerName = myProvider.getPresentableName();
|
||||
return sanitizeName(providerName);
|
||||
}
|
||||
|
||||
assert myUrl != null;
|
||||
int index = StringUtil.lastIndexOfAny(myUrl, "/\\");
|
||||
if (index == -1) return sanitizeName(myUrl);
|
||||
String possibleName = sanitizeName(myUrl.substring(index + 1));
|
||||
if (!isVeryDumbName(possibleName)) {
|
||||
return possibleName;
|
||||
}
|
||||
|
||||
int index2 = myUrl.lastIndexOf('/', index - 1);
|
||||
if (index2 != -1) {
|
||||
possibleName = sanitizeName(myUrl.substring(index2 + 1, index));
|
||||
}
|
||||
|
||||
// the only weird case
|
||||
if ("http://json.schemastore.org/config".equals(myUrl)) {
|
||||
return "asp.net config";
|
||||
}
|
||||
|
||||
if (!isVeryDumbName(possibleName)) {
|
||||
return possibleName;
|
||||
}
|
||||
|
||||
if (myUrl.startsWith("https://raw.githubusercontent.com/")) {
|
||||
String substring = myUrl.substring("https://raw.githubusercontent.com/".length() + 1);
|
||||
int slash = substring.indexOf('/');
|
||||
if (slash != -1) {
|
||||
int slash2 = substring.indexOf('/', slash + 1);
|
||||
if (slash2 != -1) {
|
||||
return sanitizeName(substring.substring(slash + 1, slash2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return possibleName;
|
||||
}
|
||||
|
||||
private static boolean isVeryDumbName(String possibleName) {
|
||||
return "schema".equals(possibleName) || "config".equals(possibleName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String sanitizeName(String providerName) {
|
||||
return StringUtil.trimEnd(StringUtil.trimEnd(StringUtil.trimEnd(providerName, ".json"), "-schema"), ".schema");
|
||||
}
|
||||
|
||||
public JsonSchemaVersion getSchemaVersion() {
|
||||
return myProvider != null ? myProvider.getSchemaVersion() : JsonSchemaVersion.SCHEMA_4;
|
||||
}
|
||||
}
|
||||
@@ -89,5 +89,33 @@ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderF
|
||||
public SchemaType getSchemaType() {
|
||||
return SchemaType.schema;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getRemoteSource() {
|
||||
switch (myFileName) {
|
||||
case SCHEMA_JSON_FILE_NAME:
|
||||
return "http://json-schema.org/draft-04/schema";
|
||||
case SCHEMA06_JSON_FILE_NAME:
|
||||
return "http://json-schema.org/draft-06/schema";
|
||||
case SCHEMA07_JSON_FILE_NAME:
|
||||
return "http://json-schema.org/draft-07/schema";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
switch (myFileName) {
|
||||
case SCHEMA_JSON_FILE_NAME:
|
||||
return "JSON Schema V4";
|
||||
case SCHEMA06_JSON_FILE_NAME:
|
||||
return "JSON Schema V6";
|
||||
case SCHEMA07_JSON_FILE_NAME:
|
||||
return "JSON Schema V7";
|
||||
}
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -8,7 +8,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration;
|
||||
import com.jetbrains.jsonSchema.UserDefinedJsonSchemaConfiguration;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaVersion;
|
||||
import com.jetbrains.jsonSchema.remote.JsonFileResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -99,8 +98,7 @@ public class JsonSchemaUserDefinedProviderFactory implements JsonSchemaProviderF
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull VirtualFile file) {
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (myPatterns.isEmpty() || file.isDirectory() || !file.isValid() || getSchemaFile() == null ||
|
||||
JsonSchemaService.Impl.get(myProject).isSchemaFile(file)) return false;
|
||||
if (myPatterns.isEmpty() || file.isDirectory() || !file.isValid() || getSchemaFile() == null) return false;
|
||||
return myPatterns.stream().anyMatch(processor -> processor.process(myProject, file));
|
||||
}
|
||||
|
||||
@@ -121,5 +119,11 @@ public class JsonSchemaUserDefinedProviderFactory implements JsonSchemaProviderF
|
||||
result = 31 * result + FileUtil.pathHashCode(myFile);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getRemoteSource() {
|
||||
return isHttpPath(myFile) ? myFile : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import com.intellij.openapi.util.ModificationTracker;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaInfo;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaVersion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface JsonSchemaService {
|
||||
class Impl {
|
||||
@@ -35,6 +37,13 @@ public interface JsonSchemaService {
|
||||
@NotNull
|
||||
Collection<VirtualFile> getSchemaFilesForFile(@NotNull VirtualFile file);
|
||||
|
||||
void registerRemoteUpdateCallback(Runnable callback);
|
||||
void unregisterRemoteUpdateCallback(Runnable callback);
|
||||
void registerResetAction(Runnable action);
|
||||
void unregisterResetAction(Runnable action);
|
||||
|
||||
void triggerUpdateRemote();
|
||||
|
||||
@Nullable
|
||||
JsonSchemaObject getSchemaObject(@NotNull VirtualFile file);
|
||||
|
||||
@@ -42,7 +51,7 @@ public interface JsonSchemaService {
|
||||
JsonSchemaObject getSchemaObjectForSchemaFile(@NotNull VirtualFile schemaFile);
|
||||
|
||||
@Nullable
|
||||
VirtualFile findSchemaFileByReference(@NotNull String reference, VirtualFile referent);
|
||||
VirtualFile findSchemaFileByReference(@NotNull String reference, @Nullable VirtualFile referent);
|
||||
|
||||
@Nullable
|
||||
JsonSchemaFileProvider getSchemaProvider(@NotNull final VirtualFile schemaFile);
|
||||
@@ -51,6 +60,8 @@ public interface JsonSchemaService {
|
||||
|
||||
ModificationTracker getAnySchemaChangeTracker();
|
||||
|
||||
List<JsonSchemaInfo> getAllUserVisibleSchemas();
|
||||
|
||||
@NotNull
|
||||
static String normalizeId(@NotNull String id) {
|
||||
id = id.endsWith("#") ? id.substring(0, id.length() - 1) : id;
|
||||
|
||||
@@ -41,17 +41,6 @@ public class JsonCachedValues {
|
||||
}
|
||||
|
||||
private static final Key<CachedValue<String>> SCHEMA_URL_KEY = Key.create("JsonSchemaUrlCache");
|
||||
@Nullable
|
||||
public static VirtualFile getSchemaFileFromSchemaProperty(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
String schemaUrl = getSchemaUrlFromSchemaProperty(file, project);
|
||||
|
||||
if (schemaUrl != null) {
|
||||
VirtualFile virtualFile = JsonFileResolver.resolveSchemaByReference(file, schemaUrl);
|
||||
if (virtualFile != null) return virtualFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getSchemaUrlFromSchemaProperty(@NotNull VirtualFile file,
|
||||
@NotNull Project project) {
|
||||
@@ -76,7 +65,7 @@ public class JsonCachedValues {
|
||||
if (schema == null) return null;
|
||||
|
||||
JsonValue value = schema.getValue();
|
||||
return value instanceof JsonStringLiteral ? StringUtil.trimEnd(((JsonStringLiteral)value).getValue(), "#") : null;
|
||||
return value instanceof JsonStringLiteral ? ((JsonStringLiteral)value).getValue() : null;
|
||||
}
|
||||
|
||||
private static final Key<CachedValue<String>> SCHEMA_ID_CACHE_KEY = Key.create("JsonSchemaIdCache");
|
||||
|
||||
@@ -64,7 +64,8 @@ public class JsonSchemaConflictNotificationProvider extends EditorNotifications.
|
||||
final Collection<VirtualFile> schemaFiles = myJsonSchemaService.getSchemaFilesForFile(file);
|
||||
if (schemaFiles.size() <= 1) return null;
|
||||
|
||||
final String message = createMessage(schemaFiles);
|
||||
final String message = createMessage(schemaFiles, myJsonSchemaService,
|
||||
"; ", "<html>There are several JSON Schemas mapped to this file: ", "</html>");
|
||||
if (message == null) return null;
|
||||
|
||||
final EditorNotificationPanel panel = new EditorNotificationPanel(LightColors.RED);
|
||||
@@ -76,9 +77,13 @@ public class JsonSchemaConflictNotificationProvider extends EditorNotifications.
|
||||
return panel;
|
||||
}
|
||||
|
||||
public String createMessage(@NotNull final Collection<VirtualFile> schemaFiles) {
|
||||
public static String createMessage(@NotNull final Collection<VirtualFile> schemaFiles,
|
||||
@NotNull JsonSchemaService jsonSchemaService,
|
||||
@NotNull String separator,
|
||||
@NotNull String prefix,
|
||||
@NotNull String suffix) {
|
||||
final List<Pair<Boolean, String>> pairList = schemaFiles.stream()
|
||||
.map(file -> myJsonSchemaService.getSchemaProvider(file))
|
||||
.map(file -> jsonSchemaService.getSchemaProvider(file))
|
||||
.filter(Objects::nonNull)
|
||||
.map(provider -> Pair.create(SchemaType.userSchema.equals(provider.getSchemaType()), provider.getName()))
|
||||
.collect(Collectors.toList());
|
||||
@@ -95,6 +100,6 @@ public class JsonSchemaConflictNotificationProvider extends EditorNotifications.
|
||||
else {
|
||||
return pair.getSecond();
|
||||
}
|
||||
}).collect(Collectors.joining("; ", "<html>There are several JSON Schemas mapped to this file: ", "</html>"));
|
||||
}).collect(Collectors.joining(separator, prefix, suffix));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.openapi.util.ModificationTracker;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.http.HttpVirtualFile;
|
||||
import com.intellij.util.containers.ConcurrentList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaVfsListener;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaInfo;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaProviderFactory;
|
||||
import com.jetbrains.jsonSchema.extension.SchemaType;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
@@ -80,53 +83,143 @@ public class JsonSchemaServiceImpl implements JsonSchemaService {
|
||||
public void reset() {
|
||||
myState.reset();
|
||||
myAnyChangeCount.incrementAndGet();
|
||||
for (Runnable action: myResetActions) {
|
||||
action.run();
|
||||
}
|
||||
DaemonCodeAnalyzer.getInstance(myProject).restart();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile findSchemaFileByReference(@NotNull String reference, @Nullable VirtualFile referent) {
|
||||
final Optional<VirtualFile> optional = myState.getFiles().stream()
|
||||
.filter(file -> reference.equals(JsonCachedValues.getSchemaId(file, myProject)))
|
||||
.findFirst();
|
||||
final Optional<VirtualFile> optional = findBuiltInSchemaByReference(reference);
|
||||
return optional.orElseGet(() -> JsonFileResolver.resolveSchemaByReference(referent, JsonSchemaService.normalizeId(reference)));
|
||||
}
|
||||
|
||||
private Optional<VirtualFile> findBuiltInSchemaByReference(@NotNull String reference) {
|
||||
return myState.getFiles().stream()
|
||||
.filter(file -> JsonSchemaService.normalizeId(reference).equals(JsonCachedValues.getSchemaId(file, myProject)))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<VirtualFile> getSchemaFilesForFile(@NotNull final VirtualFile file) {
|
||||
List<VirtualFile> files = myState.getProviders().stream().filter(provider -> isProviderAvailable(file, provider))
|
||||
.map(processor -> processor.getSchemaFile()).collect(Collectors.toList());
|
||||
if (files.size() > 0) {
|
||||
return files;
|
||||
return getSchemasForFile(file, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<VirtualFile> getSchemasForFile(@NotNull VirtualFile file, boolean single) {
|
||||
List<JsonSchemaFileProvider> providers = getProvidersForFile(file);
|
||||
|
||||
// proper priority:
|
||||
// 1) user providers
|
||||
// 2) $schema property
|
||||
// 3) built-in providers
|
||||
// 4) schema catalog
|
||||
|
||||
boolean checkSchemaProperty = true;
|
||||
if (providers.stream().noneMatch(p -> p.getSchemaType() == SchemaType.userSchema)) {
|
||||
VirtualFile virtualFile = resolveFromSchemaProperty(file);
|
||||
if (virtualFile != null) return ContainerUtil.createMaybeSingletonList(virtualFile);
|
||||
checkSchemaProperty = false;
|
||||
}
|
||||
|
||||
if (!single) {
|
||||
List<VirtualFile> files = ContainerUtil.newArrayList();
|
||||
for (JsonSchemaFileProvider provider : providers) {
|
||||
VirtualFile schemaFile = provider.getSchemaFile();
|
||||
if (schemaFile != null) {
|
||||
files.add(schemaFile);
|
||||
}
|
||||
}
|
||||
if (!files.isEmpty()) {
|
||||
return files;
|
||||
}
|
||||
}
|
||||
else if (!providers.isEmpty()) {
|
||||
final JsonSchemaFileProvider selected;
|
||||
if (providers.size() > 2) return ContainerUtil.emptyList();
|
||||
if (providers.size() > 1) {
|
||||
final Optional<JsonSchemaFileProvider> userSchema =
|
||||
providers.stream().filter(provider -> SchemaType.userSchema.equals(provider.getSchemaType())).findFirst();
|
||||
if (!userSchema.isPresent()) return ContainerUtil.emptyList();
|
||||
selected = userSchema.get();
|
||||
} else selected = providers.get(0);
|
||||
VirtualFile schemaFile = selected.getSchemaFile();
|
||||
return ContainerUtil.createMaybeSingletonList(schemaFile);
|
||||
}
|
||||
|
||||
if (checkSchemaProperty) {
|
||||
VirtualFile virtualFile = resolveFromSchemaProperty(file);
|
||||
if (virtualFile != null) return ContainerUtil.createMaybeSingletonList(virtualFile);
|
||||
}
|
||||
|
||||
return ContainerUtil.createMaybeSingletonList(resolveSchemaFromOtherSources(file));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsonSchemaFileProvider> getProvidersForFile(@NotNull VirtualFile file) {
|
||||
return myState.getProviders().stream().filter(provider -> isProviderAvailable(file, provider)).collect(
|
||||
Collectors.toList());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile resolveFromSchemaProperty(@NotNull VirtualFile file) {
|
||||
String schemaUrl = JsonCachedValues.getSchemaUrlFromSchemaProperty(file, myProject);
|
||||
|
||||
if (schemaUrl != null) {
|
||||
VirtualFile virtualFile = findSchemaFileByReference(schemaUrl, file);
|
||||
if (virtualFile != null) return virtualFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<JsonSchemaInfo> getAllUserVisibleSchemas() {
|
||||
List<String> schemas = myCatalogManager.getAllCatalogSchemas();
|
||||
Collection<JsonSchemaFileProvider> providers = myState.getProviders();
|
||||
List<JsonSchemaInfo> results = ContainerUtil.newArrayListWithCapacity(schemas.size() + providers.size());
|
||||
Set<String> processedRemotes = ContainerUtil.newHashSet();
|
||||
for (JsonSchemaFileProvider provider: providers) {
|
||||
if (provider.isUserVisible()
|
||||
&& provider.getRemoteSource() != null /*currently we're unable to handle providers without URLs properly*/
|
||||
&& processedRemotes.add(provider.getRemoteSource())) {
|
||||
results.add(new JsonSchemaInfo(provider));
|
||||
}
|
||||
}
|
||||
|
||||
for (String schema: schemas) {
|
||||
if (processedRemotes.add(schema)) {
|
||||
results.add(new JsonSchemaInfo(schema));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonSchemaObject getSchemaObject(@NotNull final VirtualFile file) {
|
||||
List<JsonSchemaFileProvider> providers =
|
||||
myState.getProviders().stream().filter(provider -> isProviderAvailable(file, provider)).collect(Collectors.toList());
|
||||
Collection<VirtualFile> schemas = getSchemasForFile(file, true);
|
||||
if (schemas.size() == 0) return null;
|
||||
assert schemas.size() == 1;
|
||||
VirtualFile schemaFile = schemas.iterator().next();
|
||||
return JsonCachedValues.getSchemaObject(replaceHttpFileWithBuiltinIfNeeded(schemaFile), myProject);
|
||||
}
|
||||
|
||||
if (providers.isEmpty()) {
|
||||
VirtualFile virtualFile = resolveSchemaFromOtherSources(file);
|
||||
return virtualFile == null ? null : JsonCachedValues.getSchemaObject(virtualFile, myProject);
|
||||
private VirtualFile replaceHttpFileWithBuiltinIfNeeded(VirtualFile schemaFile) {
|
||||
// this hack is needed to handle user-defined mappings via urls
|
||||
// we cannot perform that inside corresponding provider, because it leads to recursive component dependency
|
||||
// this way we're preventing http files when a built-in schema exists
|
||||
if (schemaFile instanceof HttpVirtualFile) {
|
||||
String url = schemaFile.getUrl();
|
||||
Optional<VirtualFile> first = myState.getFiles().stream()
|
||||
.filter(f -> {
|
||||
JsonSchemaFileProvider prov = getSchemaProvider(f);
|
||||
return prov != null && !(prov.getSchemaFile() instanceof HttpVirtualFile) && url.equals(prov.getRemoteSource());
|
||||
}).findFirst();
|
||||
return first.orElse(schemaFile);
|
||||
}
|
||||
|
||||
if (providers.size() > 2) return null;
|
||||
|
||||
final JsonSchemaFileProvider selected;
|
||||
if (providers.size() > 1) {
|
||||
final Optional<JsonSchemaFileProvider> userSchema =
|
||||
providers.stream().filter(provider -> SchemaType.userSchema.equals(provider.getSchemaType())).findFirst();
|
||||
if (!userSchema.isPresent()) return null;
|
||||
selected = userSchema.get();
|
||||
} else selected = providers.get(0);
|
||||
if (selected.getSchemaFile() == null) return null;
|
||||
|
||||
return JsonCachedValues.getSchemaObject(selected.getSchemaFile(), myProject);
|
||||
return schemaFile;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -180,11 +273,36 @@ public class JsonSchemaServiceImpl implements JsonSchemaService {
|
||||
|
||||
@Nullable
|
||||
private VirtualFile resolveSchemaFromOtherSources(@NotNull VirtualFile file) {
|
||||
VirtualFile virtualFile = JsonCachedValues.getSchemaFileFromSchemaProperty(file, myProject);
|
||||
if (virtualFile != null) return virtualFile;
|
||||
return myCatalogManager.getSchemaFileForFile(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRemoteUpdateCallback(Runnable callback) {
|
||||
myCatalogManager.registerCatalogUpdateCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRemoteUpdateCallback(Runnable callback) {
|
||||
myCatalogManager.unregisterCatalogUpdateCallback(callback);
|
||||
}
|
||||
|
||||
private final ConcurrentList<Runnable> myResetActions = ContainerUtil.createConcurrentList();
|
||||
|
||||
@Override
|
||||
public void registerResetAction(Runnable action) {
|
||||
myResetActions.add(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterResetAction(Runnable action) {
|
||||
myResetActions.remove(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdateRemote() {
|
||||
myCatalogManager.triggerUpdateCatalog();
|
||||
}
|
||||
|
||||
private static class MyState {
|
||||
@NotNull private final Factory<List<JsonSchemaFileProvider>> myFactory;
|
||||
@NotNull private final AtomicClearableLazyValue<Map<VirtualFile, JsonSchemaFileProvider>> myData;
|
||||
|
||||
@@ -5,7 +5,9 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.http.FileDownloadingAdapter;
|
||||
import com.intellij.openapi.vfs.impl.http.HttpVirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.http.RemoteFileInfo;
|
||||
import com.intellij.openapi.vfs.impl.http.RemoteFileManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.impl.JsonCachedValues;
|
||||
@@ -14,6 +16,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -65,6 +68,52 @@ public class JsonSchemaCatalogManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getAllCatalogSchemas() {
|
||||
if (myCatalog != null) {
|
||||
List<Pair<Collection<String>, String>> catalog = JsonCachedValues.getSchemaCatalog(myCatalog, myProject);
|
||||
if (catalog == null) return ContainerUtil.emptyList();
|
||||
List<String> results = ContainerUtil.newArrayListWithCapacity(catalog.size());
|
||||
for (Pair<Collection<String>, String> item: catalog) {
|
||||
results.add(item.second);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
return ContainerUtil.emptyList();
|
||||
}
|
||||
|
||||
private final Map<Runnable, FileDownloadingAdapter> myDownloadingAdapters = ContainerUtil.createConcurrentWeakMap();
|
||||
public void registerCatalogUpdateCallback(Runnable callback) {
|
||||
if (myCatalog instanceof HttpVirtualFile) {
|
||||
RemoteFileInfo info = ((HttpVirtualFile)myCatalog).getFileInfo();
|
||||
if (info != null) {
|
||||
FileDownloadingAdapter adapter = new FileDownloadingAdapter() {
|
||||
@Override
|
||||
public void fileDownloaded(VirtualFile localFile) {
|
||||
callback.run();
|
||||
}
|
||||
};
|
||||
myDownloadingAdapters.put(callback, adapter);
|
||||
info.addDownloadingListener(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterCatalogUpdateCallback(Runnable callback) {
|
||||
if (!myDownloadingAdapters.containsKey(callback)) return;
|
||||
|
||||
if (myCatalog instanceof HttpVirtualFile) {
|
||||
RemoteFileInfo info = ((HttpVirtualFile)myCatalog).getFileInfo();
|
||||
if (info != null) {
|
||||
info.removeDownloadingListener(myDownloadingAdapters.get(callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void triggerUpdateCatalog() {
|
||||
JsonFileResolver.startFetchingHttpFileIfNeeded(myCatalog);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String resolveSchemaFile(@NotNull VirtualFile file, @NotNull VirtualFile catalogFile, @NotNull Project project) {
|
||||
JsonFileResolver.startFetchingHttpFileIfNeeded(catalogFile);
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.widget;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.ListSeparator;
|
||||
import com.intellij.openapi.ui.popup.PopupStep;
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurable;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration;
|
||||
import com.jetbrains.jsonSchema.UserDefinedJsonSchemaConfiguration;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaInfo;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.jetbrains.jsonSchema.widget.JsonSchemaStatusPopup.*;
|
||||
|
||||
class JsonSchemaInfoPopupStep extends BaseListPopupStep<JsonSchemaInfo> {
|
||||
private final Project myProject;
|
||||
private final VirtualFile myVirtualFile;
|
||||
@NotNull private final JsonSchemaService myService;
|
||||
private static final Icon EMPTY_ICON = JBUI.scale(EmptyIcon.create(AllIcons.General.Add.getIconWidth()));
|
||||
|
||||
public JsonSchemaInfoPopupStep(@NotNull List<JsonSchemaInfo> allSchemas, @NotNull Project project, @NotNull VirtualFile virtualFile,
|
||||
@NotNull JsonSchemaService service) {
|
||||
super(null, allSchemas);
|
||||
myProject = project;
|
||||
myVirtualFile = virtualFile;
|
||||
myService = service;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getTextFor(JsonSchemaInfo value) {
|
||||
return value.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIconFor(JsonSchemaInfo value) {
|
||||
if (value == ADD_SCHEMA) {
|
||||
return AllIcons.General.Add;
|
||||
}
|
||||
|
||||
if (value == EDIT_MAPPINGS) {
|
||||
return AllIcons.General.EditItemInSection;
|
||||
}
|
||||
|
||||
if (value == LOAD_REMOTE) {
|
||||
return AllIcons.Actions.Refresh;
|
||||
}
|
||||
|
||||
return EMPTY_ICON;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ListSeparator getSeparatorAbove(JsonSchemaInfo value) {
|
||||
List<JsonSchemaInfo> values = getValues();
|
||||
int index = values.indexOf(value);
|
||||
if (index - 1 > 0) {
|
||||
JsonSchemaInfo info = values.get(index - 1);
|
||||
if (info == EDIT_MAPPINGS) {
|
||||
return new ListSeparator("Registered schemas");
|
||||
}
|
||||
if (value.getProvider() == null && info.getProvider() != null) {
|
||||
return new ListSeparator("SchemaStore.org schemas");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PopupStep onChosen(JsonSchemaInfo selectedValue, boolean finalChoice) {
|
||||
if (finalChoice) {
|
||||
if (selectedValue == ADD_SCHEMA) {
|
||||
return doFinalStep(() -> {
|
||||
JsonSchemaMappingsConfigurable configurable = new JsonSchemaMappingsConfigurable(myProject);
|
||||
ShowSettingsUtil.getInstance().editConfigurable(myProject, configurable, () -> {
|
||||
UserDefinedJsonSchemaConfiguration configuration = configurable.addProjectSchema();
|
||||
configuration.patterns.add(new UserDefinedJsonSchemaConfiguration.Item(
|
||||
VfsUtilCore.getRelativePath(myVirtualFile, myProject.getBaseDir()), false, false));
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (selectedValue == EDIT_MAPPINGS) {
|
||||
return doFinalStep(() -> ShowSettingsUtil.getInstance().editConfigurable(myProject, new JsonSchemaMappingsConfigurable(myProject)));
|
||||
}
|
||||
else if (selectedValue == LOAD_REMOTE) {
|
||||
return doFinalStep(() -> myService.triggerUpdateRemote());
|
||||
}
|
||||
else {
|
||||
setMapping(selectedValue, myVirtualFile, myProject);
|
||||
return doFinalStep(() -> myService.reset());
|
||||
}
|
||||
}
|
||||
return PopupStep.FINAL_CHOICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpeedSearchEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void setMapping(@Nullable JsonSchemaInfo selectedValue, @NotNull VirtualFile virtualFile, @NotNull Project project) {
|
||||
JsonSchemaMappingsProjectConfiguration configuration = JsonSchemaMappingsProjectConfiguration.getInstance(project);
|
||||
|
||||
VirtualFile projectBaseDir = project.getBaseDir();
|
||||
|
||||
UserDefinedJsonSchemaConfiguration mappingForFile = configuration.findMappingForFile(virtualFile);
|
||||
if (mappingForFile != null) {
|
||||
for (UserDefinedJsonSchemaConfiguration.Item pattern : mappingForFile.patterns) {
|
||||
if (Objects.equals(VfsUtil.findRelativeFile(projectBaseDir, pattern.path), virtualFile)) {
|
||||
mappingForFile.patterns.remove(pattern);
|
||||
if (mappingForFile.patterns.size() == 0) {
|
||||
configuration.removeConfiguration(mappingForFile);
|
||||
}
|
||||
else {
|
||||
mappingForFile.refreshPatterns();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedValue == null) return;
|
||||
|
||||
String path = VfsUtilCore.getRelativePath(virtualFile, projectBaseDir);
|
||||
|
||||
UserDefinedJsonSchemaConfiguration existing = configuration.findMappingBySchemaInfo(selectedValue);
|
||||
UserDefinedJsonSchemaConfiguration.Item item = new UserDefinedJsonSchemaConfiguration.Item(path, false, false);
|
||||
if (existing != null) {
|
||||
existing.patterns.add(item);
|
||||
existing.refreshPatterns();
|
||||
}
|
||||
else {
|
||||
configuration.addConfiguration(new UserDefinedJsonSchemaConfiguration(selectedValue.getDescription(),
|
||||
selectedValue.getSchemaVersion(),
|
||||
selectedValue.getUrl(),
|
||||
false,
|
||||
Collections.singletonList(item)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.widget;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.ListPopup;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaInfo;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class JsonSchemaStatusPopup {
|
||||
static final JsonSchemaInfo ADD_SCHEMA = new JsonSchemaInfo("") {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Add new schema";
|
||||
}
|
||||
};
|
||||
|
||||
static final JsonSchemaInfo EDIT_MAPPINGS = new JsonSchemaInfo("") {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Edit schema mappings";
|
||||
}
|
||||
};
|
||||
|
||||
static final JsonSchemaInfo LOAD_REMOTE = new JsonSchemaInfo("") {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Load SchemaStore mappings";
|
||||
}
|
||||
};
|
||||
|
||||
static ListPopup createPopup(@NotNull JsonSchemaService service,
|
||||
@NotNull Project project,
|
||||
@NotNull VirtualFile virtualFile,
|
||||
boolean showOnlyEdit) {
|
||||
JsonSchemaInfoPopupStep step = createPopupStep(service, project, virtualFile, showOnlyEdit);
|
||||
return JBPopupFactory.getInstance().createListPopup(step);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static JsonSchemaInfoPopupStep createPopupStep(@NotNull JsonSchemaService service,
|
||||
@NotNull Project project,
|
||||
@NotNull VirtualFile virtualFile, boolean showOnlyEdit) {
|
||||
List<JsonSchemaInfo> allSchemas;
|
||||
if (!showOnlyEdit) {
|
||||
List<JsonSchemaInfo> infos = service.getAllUserVisibleSchemas();
|
||||
Comparator<JsonSchemaInfo> comparator = Comparator.comparing(JsonSchemaInfo::getDescription, String::compareTo);
|
||||
Stream<JsonSchemaInfo> registered = infos.stream().filter(i -> i.getProvider() != null).sorted(comparator);
|
||||
List<JsonSchemaInfo> otherList = infos.stream().filter(i -> i.getProvider() == null).sorted(comparator).collect(Collectors.toList());
|
||||
if (otherList.size() == 0) {
|
||||
otherList = ContainerUtil.createMaybeSingletonList(LOAD_REMOTE);
|
||||
}
|
||||
allSchemas = Stream.concat(registered, otherList.stream()).collect(Collectors.toList());
|
||||
allSchemas.add(0, ADD_SCHEMA);
|
||||
allSchemas.add(1, EDIT_MAPPINGS);
|
||||
}
|
||||
else {
|
||||
allSchemas = ContainerUtil.createMaybeSingletonList(EDIT_MAPPINGS);
|
||||
}
|
||||
return new JsonSchemaInfoPopupStep(allSchemas, project, virtualFile, service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.widget;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.ListPopup;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.http.FileDownloadingAdapter;
|
||||
import com.intellij.openapi.vfs.impl.http.HttpVirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.http.RemoteFileInfo;
|
||||
import com.intellij.openapi.wm.StatusBar;
|
||||
import com.intellij.openapi.wm.StatusBarWidget;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.impl.status.EditorBasedStatusBarPopup;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
import com.jetbrains.jsonSchema.extension.SchemaType;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaConflictNotificationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JsonSchemaStatusWidget {
|
||||
private final Project myProject;
|
||||
private final JsonSchemaService myService;
|
||||
|
||||
@Nullable
|
||||
private MyWidget myWidget;
|
||||
private final Runnable myUpdateCallback = () -> {
|
||||
if (myWidget != null) {
|
||||
myWidget.update();
|
||||
}
|
||||
};
|
||||
|
||||
public JsonSchemaStatusWidget(final Project project) {
|
||||
myProject = project;
|
||||
myService = JsonSchemaService.Impl.get(project);
|
||||
myService.registerRemoteUpdateCallback(myUpdateCallback);
|
||||
myService.registerResetAction(myUpdateCallback);
|
||||
showOrHideWidget(false);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
myService.unregisterRemoteUpdateCallback(myUpdateCallback);
|
||||
myService.unregisterResetAction(myUpdateCallback);
|
||||
showOrHideWidget(true);
|
||||
}
|
||||
|
||||
private void showOrHideWidget(boolean forceRemove) {
|
||||
StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject);
|
||||
if (statusBar == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showWidget = !forceRemove;
|
||||
if (showWidget) {
|
||||
if (myWidget == null) {
|
||||
myWidget = new MyWidget(myProject);
|
||||
statusBar.addWidget(myWidget, myWidget.getAnchor());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (myWidget != null) {
|
||||
statusBar.removeWidget(myWidget.ID());
|
||||
myWidget = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyWidget extends EditorBasedStatusBarPopup {
|
||||
public MyWidget(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
private class MyWidgetState extends WidgetState {
|
||||
boolean warning = false;
|
||||
public MyWidgetState(String toolTip, String text, boolean actionEnabled) {
|
||||
super(toolTip, text, actionEnabled);
|
||||
}
|
||||
|
||||
public boolean isWarning() {
|
||||
return warning;
|
||||
}
|
||||
|
||||
public void setWarning(boolean warning) {
|
||||
this.warning = warning;
|
||||
this.setIcon(warning ? AllIcons.General.Warning : null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected WidgetState getWidgetState(@Nullable VirtualFile file) {
|
||||
if (file == null) {
|
||||
return new MyWidgetState("", "", false);
|
||||
}
|
||||
FileType fileType = file.getFileType();
|
||||
if (!(fileType instanceof LanguageFileType) || !(((LanguageFileType)fileType).getLanguage() instanceof JsonLanguage)) {
|
||||
WidgetState state = new MyWidgetState("", "", true);
|
||||
state.setHidden(true);
|
||||
return state;
|
||||
}
|
||||
|
||||
Collection<VirtualFile> schemaFiles = myService.getSchemaFilesForFile(file);
|
||||
if (schemaFiles.size() == 0) {
|
||||
return new MyWidgetState("No JSON Schema defined", "No JSON schema", true);
|
||||
}
|
||||
|
||||
if (schemaFiles.size() != 1) {
|
||||
List<VirtualFile> onlyUserSchemas = schemaFiles.stream().filter(s -> {
|
||||
JsonSchemaFileProvider provider = myService.getSchemaProvider(s);
|
||||
return provider != null && provider.getSchemaType() == SchemaType.userSchema;
|
||||
}).collect(Collectors.toList());
|
||||
if (onlyUserSchemas.size() > 1) {
|
||||
MyWidgetState state = new MyWidgetState(JsonSchemaConflictNotificationProvider.createMessage(schemaFiles, myService,
|
||||
"<br/>", "Conflicting schemas:<br/>", ""),
|
||||
schemaFiles.size() + " schemas (!)", true);
|
||||
state.setWarning(true);
|
||||
return state;
|
||||
}
|
||||
schemaFiles = onlyUserSchemas;
|
||||
if (schemaFiles.size() == 0) {
|
||||
return new MyWidgetState("No JSON Schema defined", "No JSON schema", true);
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFile schemaFile = schemaFiles.iterator().next();
|
||||
JsonSchemaFileProvider provider = myService.getSchemaProvider(schemaFile);
|
||||
if (provider != null) {
|
||||
String providerName = provider.getPresentableName();
|
||||
String shortName = StringUtil.trimEnd(StringUtil.trimEnd(providerName, ".json"), "-schema");
|
||||
String name = shortName.startsWith("JSON Schema") ? shortName : ("JSON Schema: " + shortName);
|
||||
String kind = provider.getSchemaType() == SchemaType.embeddedSchema || provider.getSchemaType() == SchemaType.schema ? " (bundled)" : "";
|
||||
return new MyWidgetState("JSON Schema: " + providerName + kind, name, true);
|
||||
}
|
||||
if (schemaFile instanceof HttpVirtualFile) {
|
||||
RemoteFileInfo info = ((HttpVirtualFile)schemaFile).getFileInfo();
|
||||
if (info == null) {
|
||||
MyWidgetState state = new MyWidgetState("Error downloading schema", "JSON schema error", true);
|
||||
state.setWarning(true);
|
||||
return state;
|
||||
}
|
||||
|
||||
//noinspection EnumSwitchStatementWhichMissesCases
|
||||
switch (info.getState()) {
|
||||
case DOWNLOADING_NOT_STARTED:
|
||||
case DOWNLOADING_IN_PROGRESS:
|
||||
info.addDownloadingListener(new FileDownloadingAdapter() {
|
||||
@Override
|
||||
public void fileDownloaded(VirtualFile localFile) {
|
||||
if (myWidget != null) {
|
||||
myWidget.update();
|
||||
}
|
||||
}
|
||||
});
|
||||
return new MyWidgetState("Download is scheduled or in progress", "Downloading JSON schema", false);
|
||||
case ERROR_OCCURRED:
|
||||
MyWidgetState state = new MyWidgetState("Error downloading schema", "JSON schema error", true);
|
||||
state.setWarning(true);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
if (!myService.isSchemaFile(schemaFile)) {
|
||||
MyWidgetState state = new MyWidgetState("File is not a schema", "JSON schema error", true);
|
||||
state.setWarning(true);
|
||||
return state;
|
||||
}
|
||||
|
||||
return new MyWidgetState("JSON Schema: " + getSchemaFileDesc(schemaFile), "JSON Schema: " + schemaFile.getNameWithoutExtension(), true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSchemaFileDesc(VirtualFile schemaFile) {
|
||||
if (schemaFile instanceof HttpVirtualFile) {
|
||||
return schemaFile.getPresentableUrl();
|
||||
}
|
||||
return schemaFile.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ListPopup createPopup(DataContext context) {
|
||||
final VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(context);
|
||||
if (virtualFile == null) return null;
|
||||
|
||||
Project project = getProject();
|
||||
return doCreatePopup(virtualFile, project, ((MyWidgetState)getWidgetState(virtualFile)).isWarning());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ListPopup doCreatePopup(VirtualFile virtualFile, Project project, boolean showOnlyEdit) {
|
||||
return JsonSchemaStatusPopup.createPopup(myService, project, virtualFile, showOnlyEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerCustomListeners() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StatusBarWidget createInstance(Project project) {
|
||||
return new MyWidget(project);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String ID() {
|
||||
return "JSONSchemaSelector";
|
||||
}
|
||||
|
||||
public String getAnchor() {
|
||||
return "after " + (SystemInfo.isMac ? "Encoding" : "InsertOverwrite");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.widget;
|
||||
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
public class JsonWidgetProvider extends AbstractProjectComponent {
|
||||
private JsonSchemaStatusWidget myWidget;
|
||||
|
||||
protected JsonWidgetProvider(Project project) {
|
||||
super(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpened() {
|
||||
myWidget = new JsonSchemaStatusWidget(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed() {
|
||||
myWidget.destroy();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,9 @@
|
||||
</application-components>
|
||||
|
||||
<project-components>
|
||||
<!-- Add your project components here -->
|
||||
<component>
|
||||
<implementation-class>com.jetbrains.jsonSchema.widget.JsonWidgetProvider</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
Reference in New Issue
Block a user