mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -34,14 +34,14 @@ import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -167,21 +167,8 @@ public class InternetAttachSourceProvider implements AttachSourcesProvider {
|
||||
}
|
||||
|
||||
try {
|
||||
File tmpDownload = HttpRequests.request(artifactUrl).connect(new HttpRequests.RequestProcessor<File>() {
|
||||
@Override
|
||||
public File process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
File tmpDownload = FileUtil.createTempFile(libSourceDir, "download.", ".tmp", false, false);
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpDownload));
|
||||
try {
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), out, request.getConnection().getContentLength());
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
return tmpDownload;
|
||||
}
|
||||
});
|
||||
|
||||
File tmpDownload = FileUtil.createTempFile(libSourceDir, "download.", ".tmp", false, false);
|
||||
HttpRequests.request(artifactUrl).saveToFile(tmpDownload, indicator);
|
||||
if (!sourceFile.exists() && !tmpDownload.renameTo(sourceFile)) {
|
||||
LOG.warn("Failed to rename file " + tmpDownload + " to " + sourceFileName);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class JavaDocExternalFilter extends AbstractExternalFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RefConvertor[] getRefConvertors() {
|
||||
protected RefConvertor[] getRefConverters() {
|
||||
return myReferenceConvertors;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ package com.intellij.psi.augment;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiTypeElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -44,4 +47,28 @@ public abstract class PsiAugmentProvider {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends {@link PsiTypeElement#getType()} so type could be retrieved from external place
|
||||
* e.g. from variable initializer in lombok case (http://projectlombok.org/features/val.html)
|
||||
*
|
||||
* @param typeElement place where inference takes place,
|
||||
* also nested PsiTypeElement-s (e.g. for List<String> PsiTypeElements corresponding to both List and String would be suggested)
|
||||
* @return inferred type or null, if inference is not applicable
|
||||
*/
|
||||
@Nullable
|
||||
protected PsiType inferType(PsiTypeElement typeElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getInferredType(PsiTypeElement typeElement) {
|
||||
for (PsiAugmentProvider provider : Extensions.getExtensions(EP_NAME)) {
|
||||
final PsiType type = provider.inferType(typeElement);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
@@ -76,6 +77,11 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
}
|
||||
|
||||
private PsiType calculateType() {
|
||||
final PsiType inferredType = PsiAugmentProvider.getInferredType(this);
|
||||
if (inferredType != null) {
|
||||
return inferredType;
|
||||
}
|
||||
|
||||
PsiType type = null;
|
||||
SmartList<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import lombok.val;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
<error descr="Incompatible types. Found: 'int', required: 'lombok.val'">val field = 0;</error>
|
||||
|
||||
void method(val param) {
|
||||
<error descr="Incompatible types. Found: 'lombok.val', required: 'int'">int p = param;</error>
|
||||
|
||||
val i = 0;
|
||||
int j = i + 1;
|
||||
|
||||
val a = new ArrayList<String>();
|
||||
Object o = a.get(0);
|
||||
|
||||
val b = new ArrayList<>();
|
||||
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String s = b.get(0);</error>
|
||||
o = b.get(0);
|
||||
|
||||
for (val v : a) {
|
||||
String vStr = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PsiAugmentProviderTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
private static final String LOMBOK_VAL_FQN = "lombok.val";
|
||||
private static final String LOMBOK_VAL_SHORT_NAME = "val";
|
||||
|
||||
public void testLombokVal() {
|
||||
PlatformTestUtil.registerExtension(PsiAugmentProvider.EP_NAME, new PsiAugmentProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public <Psi extends PsiElement> List<Psi> getAugments(@NotNull PsiElement element, @NotNull Class<Psi> type) {
|
||||
return Collections.<Psi>emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiType inferType(PsiTypeElement typeElement) {
|
||||
final PsiElement parent = typeElement.getParent();
|
||||
if (parent instanceof PsiLocalVariable && ((PsiLocalVariable)parent).getInitializer() != null ||
|
||||
parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiForeachStatement) {
|
||||
final String text = typeElement.getText();
|
||||
if (LOMBOK_VAL_SHORT_NAME.equals(text) || LOMBOK_VAL_FQN.equals(text)) {
|
||||
final PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement();
|
||||
if (referenceElement != null) {
|
||||
final PsiElement resolve = referenceElement.resolve();
|
||||
if (resolve instanceof PsiClass) {
|
||||
if (parent instanceof PsiLocalVariable) {
|
||||
final PsiExpression initializer = ((PsiVariable)parent).getInitializer();
|
||||
assertNotNull(initializer);
|
||||
final PsiType initializerType = initializer.getType();
|
||||
if (initializer instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement reference = ((PsiNewExpression)initializer).getClassOrAnonymousClassReference();
|
||||
if (reference != null) {
|
||||
final PsiReferenceParameterList parameterList = reference.getParameterList();
|
||||
if (parameterList != null) {
|
||||
final PsiTypeElement[] elements = parameterList.getTypeParameterElements();
|
||||
if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) {
|
||||
return TypeConversionUtil.erasure(initializerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return initializerType;
|
||||
}
|
||||
final PsiForeachStatement foreachStatement = (PsiForeachStatement)((PsiParameter)parent).getDeclarationScope();
|
||||
assertNotNull(foreachStatement);
|
||||
final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
|
||||
if (iteratedValue != null) {
|
||||
return JavaGenericsUtil.getCollectionItemType(iteratedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, myTestRootDisposable);
|
||||
myFixture.addClass("package lombok; public @interface val{}");
|
||||
myFixture.testHighlighting(false, false, false, getTestName(false) + ".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/augment";
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -71,12 +71,12 @@ public class ExternalJavadocPresentationTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBuildFromStream(String surl, Reader input, StringBuffer data, boolean search4Encoding) throws IOException {
|
||||
super.doBuildFromStream(surl, input, data, search4Encoding);
|
||||
public void doBuildFromStream(String url, Reader input, StringBuilder data, boolean search4Encoding) throws IOException {
|
||||
super.doBuildFromStream(url, input, data, search4Encoding);
|
||||
}
|
||||
}
|
||||
JavadocExternalTestFilter filter = new JavadocExternalTestFilter(getProject());
|
||||
final StringBuffer extractedData = new StringBuffer();
|
||||
StringBuilder extractedData = new StringBuilder();
|
||||
filter.doBuildFromStream(url, new StringReader(LoadTextUtil.loadText(pageTextFile).toString()), extractedData, false);
|
||||
assertEquals(LoadTextUtil.loadText(expectedTextFile).toString(), extractedData.toString());
|
||||
}
|
||||
|
||||
+117
-130
@@ -20,8 +20,6 @@ import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
@@ -31,8 +29,8 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.io.UrlConnectionUtil;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -40,54 +38,53 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* @author db
|
||||
* @since May 2, 2003
|
||||
*/
|
||||
public abstract class AbstractExternalFilter {
|
||||
private static final Logger LOG = Logger.getInstance(AbstractExternalFilter.class);
|
||||
|
||||
private static final boolean EXTRACT_IMAGES_FROM_JARS = SystemProperties.getBooleanProperty("extract.doc.images", true);
|
||||
|
||||
@NotNull public static final String QUICK_DOC_DIR_NAME = "quickdoc";
|
||||
@NotNull
|
||||
@NonNls
|
||||
public static final String QUICK_DOC_DIR_NAME = "quickdoc";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.javadoc.JavaDocExternalFilter");
|
||||
|
||||
private static final Pattern ourClassDataStartPattern = Pattern.compile("START OF CLASS DATA", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ourClassDataEndPattern = Pattern.compile("SUMMARY ========", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ourClassDataStartPattern = Pattern.compile("START OF CLASS DATA", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ourClassDataEndPattern = Pattern.compile("SUMMARY ========", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern ourNonClassDataEndPattern = Pattern.compile("<A NAME=", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
protected static @NonNls final Pattern ourAnchorsuffix = Pattern.compile("#(.*)$");
|
||||
protected static @NonNls final Pattern ourHTMLFilesuffix = Pattern.compile("/([^/]*[.][hH][tT][mM][lL]?)$");
|
||||
private static @NonNls final Pattern ourAnnihilator = Pattern.compile("/[^/^.]*/[.][.]/");
|
||||
private static @NonNls final Pattern ourIMGselector =
|
||||
@NonNls
|
||||
protected static final Pattern ourAnchorSuffix = Pattern.compile("#(.*)$");
|
||||
protected static @NonNls final Pattern ourHtmlFileSuffix = Pattern.compile("/([^/]*[.][hH][tT][mM][lL]?)$");
|
||||
private static @NonNls final Pattern ourAnnihilator = Pattern.compile("/[^/^.]*/[.][.]/");
|
||||
private static @NonNls final Pattern ourImgSelector =
|
||||
Pattern.compile("<IMG[ \\t\\n\\r\\f]+SRC=\"([^>]*?)\"", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
|
||||
private static @NonNls final Pattern ourPathInsideJarPattern = Pattern.compile(
|
||||
private static @NonNls final Pattern ourPathInsideJarPattern = Pattern.compile(
|
||||
String.format("%s(.+\\.jar)!/(.+?)[^/]+", JarFileSystem.PROTOCOL_PREFIX),
|
||||
Pattern.CASE_INSENSITIVE | Pattern.DOTALL
|
||||
);
|
||||
private static @NonNls final String JAR_PROTOCOL = "jar:";
|
||||
@NonNls private static final String HR = "<HR>";
|
||||
@NonNls private static final String P = "<P>";
|
||||
@NonNls private static final String DL = "<DL>";
|
||||
@NonNls protected static final String H2 = "</H2>";
|
||||
@NonNls protected static final String HTML_CLOSE = "</HTML>";
|
||||
@NonNls protected static final String HTML = "<HTML>";
|
||||
@NonNls private static final String BR = "<BR>";
|
||||
@NonNls private static final String DT = "<DT>";
|
||||
private static final Pattern CHARSET_META_PATTERN =
|
||||
private static @NonNls final String JAR_PROTOCOL = "jar:";
|
||||
@NonNls private static final String HR = "<HR>";
|
||||
@NonNls private static final String P = "<P>";
|
||||
@NonNls private static final String DL = "<DL>";
|
||||
@NonNls protected static final String H2 = "</H2>";
|
||||
@NonNls protected static final String HTML_CLOSE = "</HTML>";
|
||||
@NonNls protected static final String HTML = "<HTML>";
|
||||
@NonNls private static final String BR = "<BR>";
|
||||
@NonNls private static final String DT = "<DT>";
|
||||
private static final Pattern CHARSET_META_PATTERN =
|
||||
Pattern.compile("<meta[^>]+\\s*charset=\"?([\\w\\-]*)\\s*\">", Pattern.CASE_INSENSITIVE);
|
||||
private static final String FIELD_SUMMARY = "<!-- =========== FIELD SUMMARY =========== -->";
|
||||
private static final String CLASS_SUMMARY = "<div class=\"summary\">";
|
||||
private final HttpConfigurable myHttpConfigurable = HttpConfigurable.getInstance();
|
||||
private static final String FIELD_SUMMARY = "<!-- =========== FIELD SUMMARY =========== -->";
|
||||
private static final String CLASS_SUMMARY = "<div class=\"summary\">";
|
||||
|
||||
protected static abstract class RefConvertor {
|
||||
@NotNull private final Pattern mySelector;
|
||||
@NotNull
|
||||
private final Pattern mySelector;
|
||||
|
||||
public RefConvertor(@NotNull Pattern selector) {
|
||||
mySelector = selector;
|
||||
@@ -124,7 +121,7 @@ public abstract class AbstractExternalFilter {
|
||||
}
|
||||
}
|
||||
|
||||
protected final RefConvertor myIMGConvertor = new RefConvertor(ourIMGselector) {
|
||||
protected final RefConvertor myIMGConvertor = new RefConvertor(ourImgSelector) {
|
||||
@Override
|
||||
protected String convertReference(String root, String href) {
|
||||
if (StringUtil.startsWithChar(href, '#')) {
|
||||
@@ -192,7 +189,7 @@ public abstract class AbstractExternalFilter {
|
||||
root = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, "/" + path);
|
||||
}
|
||||
}
|
||||
return ourHTMLFilesuffix.matcher(root).replaceAll("/") + href;
|
||||
return ourHtmlFileSuffix.matcher(root).replaceAll("/") + href;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -210,39 +207,40 @@ public abstract class AbstractExternalFilter {
|
||||
public String correctRefs(String root, String read) {
|
||||
String result = read;
|
||||
|
||||
for (RefConvertor myReferenceConvertor : getRefConvertors()) {
|
||||
for (RefConvertor myReferenceConvertor : getRefConverters()) {
|
||||
result = myReferenceConvertor.refFilter(root, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract RefConvertor[] getRefConvertors();
|
||||
protected abstract RefConvertor[] getRefConverters();
|
||||
|
||||
@Nullable
|
||||
private static Reader getReaderByUrl(final String surl, final HttpConfigurable httpConfigurable, final ProgressIndicator pi)
|
||||
throws IOException
|
||||
{
|
||||
if (surl.startsWith(JAR_PROTOCOL)) {
|
||||
VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(BrowserUtil.getDocURL(surl));
|
||||
private static void getReaderByUrl(@NotNull String url, final @NotNull ThrowableConsumer<Reader, IOException> consumer)
|
||||
throws IOException {
|
||||
if (url.startsWith(JAR_PROTOCOL)) {
|
||||
VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(BrowserUtil.getDocURL(url));
|
||||
if (file != null) {
|
||||
consumer.consume(new StringReader(VfsUtilCore.loadText(file)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
final URL parsedUrl = BrowserUtil.getURL(url);
|
||||
if (parsedUrl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
HttpRequests.request(parsedUrl.toString()).connect(new HttpRequests.RequestProcessor<Void>() {
|
||||
@Override
|
||||
public Void process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
String contentEncoding = guessEncoding(parsedUrl);
|
||||
InputStream inputStream = request.getInputStream();
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
consumer.consume(contentEncoding != null ? new MyReader(inputStream, contentEncoding) : new MyReader(inputStream));
|
||||
return null;
|
||||
}
|
||||
|
||||
return new StringReader(VfsUtilCore.loadText(file));
|
||||
}
|
||||
|
||||
URL url = BrowserUtil.getURL(surl);
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
final URLConnection urlConnection = httpConfigurable.openConnection(url.toString());
|
||||
final String contentEncoding = guessEncoding(url);
|
||||
final InputStream inputStream =
|
||||
pi != null ? UrlConnectionUtil.getConnectionInputStreamWithException(urlConnection, pi) : urlConnection.getInputStream();
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
return contentEncoding != null ? new MyReader(inputStream, contentEncoding) : new MyReader(inputStream);
|
||||
});
|
||||
}
|
||||
|
||||
private static String guessEncoding(URL url) {
|
||||
@@ -264,31 +262,34 @@ public abstract class AbstractExternalFilter {
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
finally {
|
||||
if (reader != null)
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public String getExternalDocInfo(final String surl) throws Exception {
|
||||
public String getExternalDocInfo(final String url) throws Exception {
|
||||
Application app = ApplicationManager.getApplication();
|
||||
if (!app.isUnitTestMode() && app.isDispatchThread() || app.isWriteAccessAllowed()) {
|
||||
LOG.error("May block indefinitely: shouldn't be called from EDT or under write lock");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (surl == null) return null;
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
if (MyJavadocFetcher.isFree()) {
|
||||
final MyJavadocFetcher fetcher = new MyJavadocFetcher(surl, new MyDocBuilder() {
|
||||
final MyJavadocFetcher fetcher = new MyJavadocFetcher(url, new MyDocBuilder() {
|
||||
@Override
|
||||
public void buildFromStream(String surl, Reader input, StringBuffer result) throws IOException {
|
||||
doBuildFromStream(surl, input, result);
|
||||
public void buildFromStream(String url, Reader input, StringBuilder result) throws IOException {
|
||||
doBuildFromStream(url, input, result);
|
||||
}
|
||||
});
|
||||
final Future<?> fetcherFuture = app.executeOnPooledThread(fetcher);
|
||||
@@ -304,7 +305,7 @@ public abstract class AbstractExternalFilter {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
final String docText = correctRefs(ourAnchorsuffix.matcher(surl).replaceAll(""), fetcher.getData());
|
||||
final String docText = correctRefs(ourAnchorSuffix.matcher(url).replaceAll(""), fetcher.getData());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Filtered JavaDoc: " + docText + "\n");
|
||||
}
|
||||
@@ -318,13 +319,12 @@ public abstract class AbstractExternalFilter {
|
||||
return getExternalDocInfo(docURL);
|
||||
}
|
||||
|
||||
protected void doBuildFromStream(String surl, Reader input, StringBuffer data) throws IOException {
|
||||
doBuildFromStream(surl, input, data, true);
|
||||
protected void doBuildFromStream(String url, Reader input, StringBuilder data) throws IOException {
|
||||
doBuildFromStream(url, input, data, true);
|
||||
}
|
||||
|
||||
protected void doBuildFromStream(String surl, Reader input, StringBuffer data, boolean search4Encoding) throws IOException {
|
||||
BufferedReader buf = new BufferedReader(input);
|
||||
Trinity<Pattern, Pattern, Boolean> settings = getParseSettings(surl);
|
||||
protected void doBuildFromStream(final String url, Reader input, final StringBuilder data, boolean search4Encoding) throws IOException {
|
||||
Trinity<Pattern, Pattern, Boolean> settings = getParseSettings(url);
|
||||
@NonNls Pattern startSection = settings.first;
|
||||
@NonNls Pattern endSection = settings.second;
|
||||
boolean useDt = settings.third;
|
||||
@@ -349,6 +349,8 @@ public abstract class AbstractExternalFilter {
|
||||
|
||||
String read;
|
||||
String contentEncoding = null;
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
BufferedReader buf = new BufferedReader(input);
|
||||
do {
|
||||
read = buf.readLine();
|
||||
if (read != null && search4Encoding && read.contains("charset")) {
|
||||
@@ -360,21 +362,23 @@ public abstract class AbstractExternalFilter {
|
||||
}
|
||||
while (read != null && !startSection.matcher(StringUtil.toUpperCase(read)).find());
|
||||
|
||||
if (input instanceof MyReader && contentEncoding != null) {
|
||||
if (!contentEncoding.equalsIgnoreCase(CharsetToolkit.UTF8) &&
|
||||
!contentEncoding.equals(((MyReader)input).getEncoding()))
|
||||
{ //restart page parsing with correct encoding
|
||||
Reader stream;
|
||||
try {
|
||||
stream = getReaderByUrl(surl, myHttpConfigurable, new ProgressIndicatorBase());
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
return;
|
||||
}
|
||||
data.delete(0, data.length());
|
||||
doBuildFromStream(surl, new MyReader(((MyReader)stream).getInputStream(), contentEncoding), data, false);
|
||||
if (input instanceof MyReader && contentEncoding != null && !contentEncoding.equalsIgnoreCase(CharsetToolkit.UTF8) &&
|
||||
!contentEncoding.equals(((MyReader)input).getEncoding())) {
|
||||
//restart page parsing with correct encoding
|
||||
try {
|
||||
final String finalContentEncoding = contentEncoding;
|
||||
getReaderByUrl(url, new ThrowableConsumer<Reader, IOException>() {
|
||||
@Override
|
||||
public void consume(Reader reader) throws IOException {
|
||||
data.delete(0, data.length());
|
||||
doBuildFromStream(url, new MyReader(((MyReader)reader).getInputStream(), finalContentEncoding), data, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (read == null) {
|
||||
@@ -386,7 +390,7 @@ public abstract class AbstractExternalFilter {
|
||||
boolean skip = false;
|
||||
|
||||
do {
|
||||
if (StringUtil.toUpperCase(read).contains(H2) && !read.toUpperCase().contains("H2")) { // read=class name in <H2>
|
||||
if (StringUtil.toUpperCase(read).contains(H2) && !read.toUpperCase(Locale.ENGLISH).contains("H2")) { // read=class name in <H2>
|
||||
data.append(H2);
|
||||
skip = true;
|
||||
}
|
||||
@@ -403,8 +407,7 @@ public abstract class AbstractExternalFilter {
|
||||
|
||||
data.append(DL);
|
||||
|
||||
StringBuffer classDetails = new StringBuffer();
|
||||
|
||||
StringBuilder classDetails = new StringBuilder();
|
||||
while (((read = buf.readLine()) != null) && !StringUtil.toUpperCase(read).equals(HR) && !StringUtil.toUpperCase(read).equals(P)) {
|
||||
if (reachTheEnd(data, read, classDetails)) return;
|
||||
appendLine(classDetails, read);
|
||||
@@ -438,9 +441,9 @@ public abstract class AbstractExternalFilter {
|
||||
/**
|
||||
* Decides what settings should be used for parsing content represented by the given url.
|
||||
*
|
||||
* @param url url which points to the target content
|
||||
* @return following data: (start interested data boundary pattern; end interested data boundary pattern;
|
||||
* replace table data by <dt>)
|
||||
* @param url url which points to the target content
|
||||
* @return following data: (start interested data boundary pattern; end interested data boundary pattern;
|
||||
* replace table data by <dt>)
|
||||
*/
|
||||
@NotNull
|
||||
protected Trinity<Pattern, Pattern, Boolean> getParseSettings(@NotNull String url) {
|
||||
@@ -448,7 +451,7 @@ public abstract class AbstractExternalFilter {
|
||||
Pattern endSection = ourClassDataEndPattern;
|
||||
boolean useDt = true;
|
||||
|
||||
Matcher anchorMatcher = ourAnchorsuffix.matcher(url);
|
||||
Matcher anchorMatcher = ourAnchorSuffix.matcher(url);
|
||||
if (anchorMatcher.find()) {
|
||||
useDt = false;
|
||||
startSection = Pattern.compile(Pattern.quote("<a name=\"" + anchorMatcher.group(1) + "\""), Pattern.CASE_INSENSITIVE);
|
||||
@@ -457,10 +460,9 @@ public abstract class AbstractExternalFilter {
|
||||
return Trinity.create(startSection, endSection, useDt);
|
||||
}
|
||||
|
||||
private static boolean reachTheEnd(StringBuffer data, String read, StringBuffer classDetails) {
|
||||
private static boolean reachTheEnd(StringBuilder data, String read, StringBuilder classDetails) {
|
||||
if (StringUtil.indexOfIgnoreCase(read, FIELD_SUMMARY, 0) != -1 ||
|
||||
StringUtil.indexOfIgnoreCase(read, CLASS_SUMMARY, 0) != -1)
|
||||
{
|
||||
StringUtil.indexOfIgnoreCase(read, CLASS_SUMMARY, 0) != -1) {
|
||||
data.append(classDetails);
|
||||
data.append(HTML_CLOSE);
|
||||
return true;
|
||||
@@ -470,8 +472,9 @@ public abstract class AbstractExternalFilter {
|
||||
|
||||
@Nullable
|
||||
static String parseContentEncoding(@NotNull String htmlLine) {
|
||||
if (!htmlLine.contains("charset"))
|
||||
if (!htmlLine.contains("charset")) {
|
||||
return null;
|
||||
}
|
||||
final Matcher matcher = CHARSET_META_PATTERN.matcher(htmlLine);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
@@ -479,28 +482,27 @@ public abstract class AbstractExternalFilter {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void appendLine(final StringBuffer buffer, final String read) {
|
||||
private static void appendLine(StringBuilder buffer, final String read) {
|
||||
buffer.append(read);
|
||||
buffer.append("\n");
|
||||
}
|
||||
|
||||
private interface MyDocBuilder {
|
||||
void buildFromStream(String surl, Reader input, StringBuffer result) throws IOException;
|
||||
void buildFromStream(String url, Reader input, StringBuilder result) throws IOException;
|
||||
}
|
||||
|
||||
private static class MyJavadocFetcher implements Runnable {
|
||||
private static boolean ourFree = true;
|
||||
private final StringBuffer data = new StringBuffer();
|
||||
private final String surl;
|
||||
private static boolean ourFree = true;
|
||||
private final StringBuilder data = new StringBuilder();
|
||||
private final String url;
|
||||
private final MyDocBuilder myBuilder;
|
||||
private final Exception[] myExceptions = new Exception[1];
|
||||
private final HttpConfigurable myHttpConfigurable;
|
||||
private Exception myException;
|
||||
|
||||
public MyJavadocFetcher(final String surl, MyDocBuilder builder) {
|
||||
this.surl = surl;
|
||||
public MyJavadocFetcher(String url, MyDocBuilder builder) {
|
||||
this.url = url;
|
||||
myBuilder = builder;
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
ourFree = false;
|
||||
myHttpConfigurable = HttpConfigurable.getInstance();
|
||||
}
|
||||
|
||||
public static boolean isFree() {
|
||||
@@ -514,51 +516,36 @@ public abstract class AbstractExternalFilter {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (surl == null) {
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reader stream = null;
|
||||
try {
|
||||
stream = getReaderByUrl(surl, myHttpConfigurable, new ProgressIndicatorBase());
|
||||
getReaderByUrl(url, new ThrowableConsumer<Reader, IOException>() {
|
||||
@Override
|
||||
public void consume(Reader reader) throws IOException {
|
||||
myBuilder.buildFromStream(url, reader, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
return;
|
||||
catch (ProcessCanceledException ignored) {
|
||||
}
|
||||
catch (IOException e) {
|
||||
myExceptions[0] = e;
|
||||
}
|
||||
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
myBuilder.buildFromStream(surl, stream, data);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
myExceptions[0] = e;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
myExceptions[0] = e;
|
||||
}
|
||||
myException = e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
ourFree = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return myExceptions[0];
|
||||
return myException;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
myExceptions[0] = null;
|
||||
myException = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,19 +37,19 @@ import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.concurrency.BoundedTaskExecutor;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import com.intellij.util.download.DownloadableFileDescription;
|
||||
import com.intellij.util.download.FileDownloader;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.net.IOExceptionDialog;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.ide.PooledThreadExecutor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -315,22 +315,8 @@ public class FileDownloaderImpl implements FileDownloader {
|
||||
return existingFile;
|
||||
}
|
||||
|
||||
File tempFile = FileUtil.createTempFile("download.", ".tmp");
|
||||
boolean deleteFile = true;
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(tempFile));
|
||||
try {
|
||||
indicator.setText2(IdeBundle.message("progress.download.file.text", description.getPresentableFileName(), presentableUrl));
|
||||
indicator.setIndeterminate(size == -1);
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), out, size);
|
||||
deleteFile = false;
|
||||
return tempFile;
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
if (deleteFile) {
|
||||
FileUtil.delete(tempFile);
|
||||
}
|
||||
}
|
||||
indicator.setText2(IdeBundle.message("progress.download.file.text", description.getPresentableFileName(), presentableUrl));
|
||||
return request.saveToFile(FileUtil.createTempFile("download.", ".tmp"), indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,17 +19,21 @@ import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
@@ -58,6 +62,11 @@ public abstract class HttpRequests {
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
boolean isSuccessful() throws IOException;
|
||||
|
||||
@NotNull
|
||||
File saveToFile(@NotNull File file, @Nullable ProgressIndicator indicator) throws IOException;
|
||||
|
||||
byte[] toBytes(@Nullable ProgressIndicator indicator) throws IOException;
|
||||
}
|
||||
|
||||
public interface RequestProcessor<T> {
|
||||
@@ -154,6 +163,26 @@ public abstract class HttpRequests {
|
||||
return errorValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void saveToFile(@NotNull final File file, @Nullable final ProgressIndicator indicator) throws IOException {
|
||||
connect(new HttpRequests.RequestProcessor<Void>() {
|
||||
@Override
|
||||
public Void process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
request.saveToFile(file, indicator);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public byte[] toBytes(@Nullable final ProgressIndicator indicator) throws IOException {
|
||||
return connect(new HttpRequests.RequestProcessor<byte[]>() {
|
||||
@Override
|
||||
public byte[] process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
return request.toBytes(indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -216,6 +245,53 @@ public abstract class HttpRequests {
|
||||
((HttpURLConnection)myConnection).disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public byte[] toBytes(@Nullable ProgressIndicator indicator) throws IOException {
|
||||
int contentLength = getConnection().getContentLength();
|
||||
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(contentLength > 0 ? contentLength : 32 * 1024);
|
||||
NetUtils.copyStreamContent(indicator, getInputStream(), out, contentLength);
|
||||
return ArrayUtil.realloc(out.getInternalBuffer(), out.size());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public File saveToFile(@NotNull File file, @Nullable ProgressIndicator indicator) throws IOException {
|
||||
OutputStream out = null;
|
||||
boolean deleteFile = true;
|
||||
try {
|
||||
if (indicator != null) {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
|
||||
FileUtilRt.createParentDirs(file);
|
||||
out = new FileOutputStream(file);
|
||||
NetUtils.copyStreamContent(indicator, getInputStream(), out, getConnection().getContentLength());
|
||||
deleteFile = false;
|
||||
}
|
||||
catch (IOException e) {
|
||||
URLConnection connection = getConnection();
|
||||
String errorMessage = "Cannot download '" + builder.myUrl + ", headers: " + connection.getHeaderFields();
|
||||
if (connection instanceof HttpURLConnection) {
|
||||
HttpURLConnection httpConnection = (HttpURLConnection)connection;
|
||||
errorMessage += "', response code: " + httpConnection.getResponseCode()
|
||||
+ ", response message: " + httpConnection.getResponseMessage();
|
||||
}
|
||||
throw new IOException(errorMessage, e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (deleteFile) {
|
||||
FileUtilRt.delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
RequestImpl request = new RequestImpl();
|
||||
|
||||
@@ -178,12 +178,11 @@ class HttpProxySettingsUi implements ConfigurableUi<HttpConfigurable> {
|
||||
//noinspection ConstantConditions
|
||||
HttpRequests.request(answer)
|
||||
.readTimeout(3 * 1000)
|
||||
.connect(new HttpRequests.RequestProcessor<Object>() {
|
||||
.connect(new HttpRequests.RequestProcessor<Void>() {
|
||||
@Override
|
||||
public Object process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
int responseCode = ((HttpURLConnection)request.getConnection()).getResponseCode();
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
exceptionReference.set(new IOException("Error code: " + responseCode));
|
||||
public Void process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
if (!request.isSuccessful()) {
|
||||
exceptionReference.set(new IOException("Error code: " + ((HttpURLConnection)request.getConnection()).getResponseCode()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.openapi.util.BuildNumber;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -36,7 +35,10 @@ import org.xml.sax.SAXException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLConnection;
|
||||
@@ -125,13 +127,7 @@ public class RepositoryHelper {
|
||||
if (pluginListFile != null) {
|
||||
synchronized (RepositoryHelper.class) {
|
||||
FileUtil.ensureExists(pluginListFile.getParentFile());
|
||||
OutputStream output = new FileOutputStream(pluginListFile);
|
||||
try {
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), output, connection.getContentLength());
|
||||
}
|
||||
finally {
|
||||
output.close();
|
||||
}
|
||||
request.saveToFile(pluginListFile, indicator);
|
||||
return loadPluginList(pluginListFile);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-14
@@ -35,12 +35,12 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.io.ZipUtil;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@@ -254,19 +254,9 @@ public class PluginDownloader {
|
||||
return HttpRequests.request(myPluginUrl).gzip(false).forceHttps(myForceHttps).connect(new HttpRequests.RequestProcessor<File>() {
|
||||
@Override
|
||||
public File process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
indicator.checkCanceled();
|
||||
|
||||
URLConnection connection = request.getConnection();
|
||||
OutputStream fileOut = new FileOutputStream(file);
|
||||
try {
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), fileOut, connection.getContentLength());
|
||||
}
|
||||
finally {
|
||||
fileOut.close();
|
||||
}
|
||||
|
||||
request.saveToFile(file, indicator);
|
||||
if (myFileName == null) {
|
||||
myFileName = guessFileName(connection, file);
|
||||
myFileName = guessFileName(request.getConnection(), file);
|
||||
}
|
||||
|
||||
File newFile = new File(file.getParentFile(), myFileName);
|
||||
|
||||
+4
-11
@@ -43,7 +43,6 @@ import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.jdom.Document;
|
||||
@@ -54,7 +53,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
@@ -587,15 +588,7 @@ public final class UpdateChecker {
|
||||
File tempFile = HttpRequests.request(url).gzip(false).forceHttps(forceHttps).connect(new HttpRequests.RequestProcessor<File>() {
|
||||
@Override
|
||||
public File process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
File tempFile = FileUtil.createTempFile("ij.platform.", ".patch", true);
|
||||
OutputStream output = new BufferedOutputStream(new FileOutputStream(tempFile));
|
||||
try {
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), output, request.getConnection().getContentLength());
|
||||
}
|
||||
finally {
|
||||
output.close();
|
||||
}
|
||||
return tempFile;
|
||||
return request.saveToFile(FileUtil.createTempFile("ij.platform.", ".patch", true), indicator);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+12
-29
@@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsBundle;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -30,7 +31,8 @@ import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.net.ssl.CertificateManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public class DefaultRemoteContentProvider extends RemoteContentProvider {
|
||||
@@ -63,39 +65,20 @@ public class DefaultRemoteContentProvider extends RemoteContentProvider {
|
||||
.connect(new HttpRequests.RequestProcessor<Object>() {
|
||||
@Override
|
||||
public Object process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
HttpURLConnection connection = (HttpURLConnection)request.getConnection();
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException(IdeBundle.message("error.connection.failed.with.http.code.N", responseCode));
|
||||
if (!request.isSuccessful()) {
|
||||
throw new IOException(IdeBundle.message("error.connection.failed.with.http.code.N", ((HttpURLConnection)request.getConnection()).getResponseCode()));
|
||||
}
|
||||
|
||||
int size = connection.getContentLength();
|
||||
OutputStream output = new BufferedOutputStream(new FileOutputStream(file));
|
||||
try {
|
||||
callback.setProgressText(VfsBundle.message("download.progress.downloading", presentableUrl), size == -1);
|
||||
if (size != -1) {
|
||||
int size = request.getConnection().getContentLength();
|
||||
callback.setProgressText(VfsBundle.message("download.progress.downloading", presentableUrl), size == -1);
|
||||
request.saveToFile(file, new AbstractProgressIndicatorExBase() {
|
||||
@Override
|
||||
public void setFraction(double fraction) {
|
||||
callback.setProgressFraction(0);
|
||||
}
|
||||
});
|
||||
|
||||
int count;
|
||||
byte[] buf = new byte[4096];
|
||||
int total = 0;
|
||||
while ((count = request.getInputStream().read(buf)) > 0) {
|
||||
if (callback.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
total += count;
|
||||
if (size > 0) {
|
||||
callback.setProgressFraction((double)total / size);
|
||||
}
|
||||
output.write(buf, 0, count);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
output.close();
|
||||
}
|
||||
|
||||
FileType fileType = RemoteFileUtil.getFileType(connection.getContentType());
|
||||
FileType fileType = RemoteFileUtil.getFileType(request.getConnection().getContentType());
|
||||
if (fileType == FileTypes.PLAIN_TEXT) {
|
||||
FileType fileTypeByFileName = FileTypeRegistry.getInstance().getFileTypeByFileName(PathUtilRt.getFileName(url.getPath()));
|
||||
if (fileTypeByFileName != FileTypes.UNKNOWN) {
|
||||
|
||||
@@ -217,6 +217,8 @@ emmet.configuration.title=Emmet
|
||||
emmet.enable.label=&Enable XML Emmet
|
||||
emmet.filters.enabled.by.default=Filters enabled by default
|
||||
emmet.enable.preview=Enable &abbreviation preview
|
||||
emmet.allow.compact.boolean.attributes=Allow &compact boolean attributes in HTML (use <div attr> instead of <div attr="attr">)
|
||||
emmet.boolean.attributes=Boolean attributes
|
||||
emmet.expand.abbreviation.with=Expand &abbreviation with
|
||||
|
||||
title.cannot.create.html.file=Cannot create HTML file
|
||||
|
||||
+3
-15
@@ -18,11 +18,9 @@ import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -141,25 +139,15 @@ public abstract class AbstractAttachSourceProvider implements AttachSourcesProvi
|
||||
|
||||
@Override
|
||||
public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
|
||||
|
||||
final ActionCallback callback = new ActionCallback();
|
||||
|
||||
Task task = new Task.Backgroundable(myProject, "Downloading sources...", true) {
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
final ByteArrayOutputStream out;
|
||||
final byte[] bytes;
|
||||
try {
|
||||
LOG.info("Downloading sources JAR: " + myUrl);
|
||||
indicator.checkCanceled();
|
||||
out = HttpRequests.request(myUrl).connect(new HttpRequests.RequestProcessor<ByteArrayOutputStream>() {
|
||||
@Override
|
||||
public ByteArrayOutputStream process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
int contentLength = request.getConnection().getContentLength();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(contentLength > 0 ? contentLength : 100 * 1024);
|
||||
NetUtils.copyStreamContent(indicator, request.getInputStream(), out, contentLength);
|
||||
return out;
|
||||
}
|
||||
});
|
||||
bytes = HttpRequests.request(myUrl).toBytes(indicator);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn(e);
|
||||
@@ -183,7 +171,7 @@ public abstract class AbstractAttachSourceProvider implements AttachSourcesProvi
|
||||
public void run() {
|
||||
AccessToken accessToken = WriteAction.start();
|
||||
try {
|
||||
storeFile(out.toByteArray());
|
||||
storeFile(bytes);
|
||||
}
|
||||
finally {
|
||||
accessToken.finish();
|
||||
|
||||
+1
-13
@@ -30,13 +30,10 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -68,19 +65,10 @@ public abstract class DownloadManager {
|
||||
file = HttpRequests.request(location).connect(new HttpRequests.RequestProcessor<File>() {
|
||||
@Override
|
||||
public File process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
int total = request.getConnection().getContentLength();
|
||||
String name = Integer.toHexString(System.identityHashCode(this)) + "_" +
|
||||
Integer.toHexString(location.hashCode()) + "_" +
|
||||
location.substring(location.lastIndexOf('/') + 1);
|
||||
File file = new File(myResourcePath, name.lastIndexOf('.') == -1 ? name + ".xml" : name);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
NetUtils.copyStreamContent(myProgress, request.getInputStream(), out, total);
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
return file;
|
||||
return request.saveToFile(new File(myResourcePath, name.lastIndexOf('.') == -1 ? name + ".xml" : name), myProgress);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
</template>
|
||||
<template description="<script>...</script>" name="script" toReformat="true" toShortenFQNames="true" value="<script>$END$</script>">
|
||||
<template description="<script>...</script>" name="script" toReformat="true" toShortenFQNames="true" value="<script !src="">$END$</script>">
|
||||
<context>
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.application.options.emmet;
|
||||
|
||||
import com.intellij.codeInsight.template.emmet.filters.BemEmmetFilter;
|
||||
import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.openapi.components.*;
|
||||
@@ -24,7 +23,6 @@ import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@State(
|
||||
@@ -32,32 +30,12 @@ import java.util.Set;
|
||||
storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/emmet.xml")
|
||||
)
|
||||
public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
/**
|
||||
* @deprecated delete after IDEA 14
|
||||
*/
|
||||
private boolean myBemFilterEnabledByDefault = false;
|
||||
private boolean myEmmetEnabled = true;
|
||||
private int myEmmetExpandShortcut = TemplateSettings.TAB_CHAR;
|
||||
private boolean myFuzzySearchEnabled = true;
|
||||
private boolean myAutoInsertCssPrefixedEnabled = true;
|
||||
private boolean myPreviewEnabled = false;
|
||||
private boolean myCompactBooleanAllowed = true;
|
||||
private Set<String> myBooleanAttributes = ContainerUtil.newHashSet("contenteditable", "seamless");
|
||||
private Set<String> myFiltersEnabledByDefault = ContainerUtil.newHashSet();
|
||||
@NotNull
|
||||
private Map<String, Integer> prefixes = ContainerUtil.newHashMap();
|
||||
|
||||
/**
|
||||
* @deprecated delete after IDEA 14
|
||||
*/
|
||||
public boolean isBemFilterEnabledByDefault() {
|
||||
return myBemFilterEnabledByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delete after IDEA 14
|
||||
*/
|
||||
public void setBemFilterEnabledByDefault(boolean enableBemFilterByDefault) {
|
||||
myBemFilterEnabledByDefault = enableBemFilterByDefault;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getFiltersEnabledByDefault() {
|
||||
@@ -70,7 +48,7 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
|
||||
public boolean isFilterEnabledByDefault(@NotNull ZenCodingFilter filter) {
|
||||
return myFiltersEnabledByDefault.contains(filter.getSuffix());
|
||||
}
|
||||
}
|
||||
|
||||
public void setEmmetExpandShortcut(int emmetExpandShortcut) {
|
||||
myEmmetExpandShortcut = emmetExpandShortcut;
|
||||
@@ -87,7 +65,23 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
public void setPreviewEnabled(boolean previewEnabled) {
|
||||
myPreviewEnabled = previewEnabled;
|
||||
}
|
||||
|
||||
|
||||
public boolean isCompactBooleanAllowed() {
|
||||
return myCompactBooleanAllowed;
|
||||
}
|
||||
|
||||
public void setCompactBooleanAllowed(boolean compactBooleanAllowed) {
|
||||
myCompactBooleanAllowed = compactBooleanAllowed;
|
||||
}
|
||||
|
||||
public Set<String> getBooleanAttributes() {
|
||||
return myBooleanAttributes;
|
||||
}
|
||||
|
||||
public void setBooleanAttributes(@NotNull Set<String> booleanAttributes) {
|
||||
myBooleanAttributes = booleanAttributes;
|
||||
}
|
||||
|
||||
public boolean isEmmetEnabled() {
|
||||
return myEmmetEnabled;
|
||||
}
|
||||
@@ -96,30 +90,6 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
myEmmetEnabled = emmetEnabled;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public boolean isAutoInsertCssPrefixedEnabled() {
|
||||
return myAutoInsertCssPrefixedEnabled;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public void setAutoInsertCssPrefixedEnabled(boolean autoInsertCssPrefixedEnabled) {
|
||||
myAutoInsertCssPrefixedEnabled = autoInsertCssPrefixedEnabled;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public void setFuzzySearchEnabled(boolean fuzzySearchEnabled) {
|
||||
myFuzzySearchEnabled = fuzzySearchEnabled;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public boolean isFuzzySearchEnabled() {
|
||||
return myFuzzySearchEnabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EmmetOptions getState() {
|
||||
@@ -129,28 +99,9 @@ public class EmmetOptions implements PersistentStateComponent<EmmetOptions> {
|
||||
@Override
|
||||
public void loadState(final EmmetOptions state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
|
||||
// todo delete after IDEA 14
|
||||
if (myFiltersEnabledByDefault.isEmpty() && myBemFilterEnabledByDefault) {
|
||||
myFiltersEnabledByDefault.add(BemEmmetFilter.SUFFIX);
|
||||
}
|
||||
}
|
||||
|
||||
public static EmmetOptions getInstance() {
|
||||
return ServiceManager.getService(EmmetOptions.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public Map<String, Integer> getPrefixes() {
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Deprecated
|
||||
//use {@link CssEmmetOptions}
|
||||
public void setPrefixes(@NotNull Map<String, Integer> prefixes) {
|
||||
this.prefixes = prefixes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="130"/>
|
||||
<xy x="20" y="20" width="999" height="135"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="369dc" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="369dc" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
@@ -38,7 +38,7 @@
|
||||
<grid id="cdbb7" binding="myFiltersListPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@@ -51,6 +51,14 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="3bd4e" class="com.intellij.ui.components.JBCheckBox" binding="myAllowCompactBooleanAttributesJBCheckBox" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/XmlBundle" key="emmet.allow.compact.boolean.attributes"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
|
||||
@@ -40,6 +40,7 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
|
||||
private JBCheckBox myEnablePreviewJBCheckBox;
|
||||
private CheckBoxList<ZenCodingFilter> myFiltersCheckBoxList;
|
||||
private JPanel myFiltersListPanel;
|
||||
private JBCheckBox myAllowCompactBooleanAttributesJBCheckBox;
|
||||
|
||||
public XmlEmmetConfigurable() {
|
||||
myEnableEmmetJBCheckBox.addActionListener(new ActionListener() {
|
||||
@@ -47,6 +48,7 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
boolean selected = myEnableEmmetJBCheckBox.isSelected();
|
||||
myEnablePreviewJBCheckBox.setEnabled(selected);
|
||||
myAllowCompactBooleanAttributesJBCheckBox.setEnabled(selected);
|
||||
myFiltersCheckBoxList.setEnabled(selected);
|
||||
}
|
||||
});
|
||||
@@ -74,6 +76,7 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
|
||||
EmmetOptions emmetOptions = EmmetOptions.getInstance();
|
||||
return emmetOptions.isEmmetEnabled() != myEnableEmmetJBCheckBox.isSelected() ||
|
||||
emmetOptions.isPreviewEnabled() != myEnablePreviewJBCheckBox.isSelected() ||
|
||||
emmetOptions.isCompactBooleanAllowed() != myAllowCompactBooleanAttributesJBCheckBox.isSelected() ||
|
||||
!emmetOptions.getFiltersEnabledByDefault().equals(enabledFilters());
|
||||
}
|
||||
|
||||
@@ -82,6 +85,7 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
|
||||
EmmetOptions emmetOptions = EmmetOptions.getInstance();
|
||||
emmetOptions.setEmmetEnabled(myEnableEmmetJBCheckBox.isSelected());
|
||||
emmetOptions.setPreviewEnabled(myEnablePreviewJBCheckBox.isSelected());
|
||||
emmetOptions.setCompactBooleanAllowed(myAllowCompactBooleanAttributesJBCheckBox.isSelected());
|
||||
emmetOptions.setFiltersEnabledByDefault(enabledFilters());
|
||||
}
|
||||
|
||||
@@ -92,6 +96,8 @@ public class XmlEmmetConfigurable implements UnnamedConfigurable, Disposable, Co
|
||||
myEnableEmmetJBCheckBox.setSelected(emmetOptions.isEmmetEnabled());
|
||||
myEnablePreviewJBCheckBox.setEnabled(emmetOptions.isEmmetEnabled());
|
||||
myEnablePreviewJBCheckBox.setSelected(emmetOptions.isPreviewEnabled());
|
||||
myAllowCompactBooleanAttributesJBCheckBox.setEnabled(emmetOptions.isEmmetEnabled());
|
||||
myAllowCompactBooleanAttributesJBCheckBox.setSelected(emmetOptions.isCompactBooleanAllowed());
|
||||
|
||||
Set<String> enabledByDefault = emmetOptions.getFiltersEnabledByDefault();
|
||||
for (ZenCodingFilter filter : ZenCodingFilter.getInstances()) {
|
||||
|
||||
+14
-27
@@ -46,9 +46,9 @@ import com.intellij.psi.search.PsiElementProcessor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.net.HttpConfigurable;
|
||||
import com.intellij.util.net.IOExceptionDialog;
|
||||
import com.intellij.util.net.NetUtils;
|
||||
import com.intellij.xml.XmlBundle;
|
||||
import com.intellij.xml.util.XmlUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -56,10 +56,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -515,30 +515,17 @@ public class FetchExtResourceAction extends BaseExtResourceAction implements Wat
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FetchResult fetchData(final Project project, final String dtdUrl, ProgressIndicator indicator) throws IOException {
|
||||
|
||||
private static FetchResult fetchData(final Project project, final String dtdUrl, final ProgressIndicator indicator) throws IOException {
|
||||
try {
|
||||
URL url = new URL(dtdUrl);
|
||||
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
|
||||
urlConnection.addRequestProperty("accept", "text/xml,application/xml,text/html,*/*");
|
||||
int contentLength = urlConnection.getContentLength();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
InputStream in = urlConnection.getInputStream();
|
||||
String contentType;
|
||||
try {
|
||||
contentType = urlConnection.getContentType();
|
||||
NetUtils.copyStreamContent(indicator, in, out, contentLength);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
FetchResult result = new FetchResult();
|
||||
result.bytes = out.toByteArray();
|
||||
result.contentType = contentType;
|
||||
|
||||
return result;
|
||||
HttpRequests.request(dtdUrl).accept("text/xml,application/xml,text/html,*/*").connect(new HttpRequests.RequestProcessor<FetchResult>() {
|
||||
@Override
|
||||
public FetchResult process(@NotNull HttpRequests.Request request) throws IOException {
|
||||
FetchResult result = new FetchResult();
|
||||
result.bytes = request.toBytes(indicator);
|
||||
result.contentType = request.getConnection().getContentType();
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
|
||||
@@ -228,4 +228,13 @@ public abstract class EmmetParser {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected ZenCodingToken nextToken(int i) {
|
||||
if (myIndex + i < myTokens.size()) {
|
||||
return myTokens.get(myIndex + i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.psi.xml.XmlTokenType;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -41,11 +42,10 @@ import java.util.regex.Pattern;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.startsWithIgnoreCase;
|
||||
|
||||
/**
|
||||
* User: zolotov
|
||||
* Date: 2/7/13
|
||||
*/
|
||||
public class XmlEmmetParser extends EmmetParser {
|
||||
public static final String DEFAULT_ATTRIBUTE_NAME = "%default";
|
||||
public static final String BOOLEAN_ATTRIBUTE_VALUE = "%boolean";
|
||||
|
||||
private static final String DEFAULT_TAG = "div";
|
||||
private static final int DEFAULT_LOREM_LENGTH = 30;
|
||||
private static final Pattern LOREM_PATTERN = Pattern.compile("(lorem|lipsum)(\\d*)");
|
||||
@@ -89,6 +89,28 @@ public class XmlEmmetParser extends EmmetParser {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getAttributeNameByToken(ZenCodingToken token) {
|
||||
if (!(token instanceof IdentifierToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String name = ((IdentifierToken)token).getText();
|
||||
|
||||
if (name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final XmlTag tag = XmlElementFactory.getInstance(myCallback.getProject()).createTagFromText("<tag " + name + "=''/>");
|
||||
XmlAttribute[] attributes = tag.getAttributes();
|
||||
if (attributes.length == 1) {
|
||||
return attributes[0].getName();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getAttributeValueByToken(@Nullable ZenCodingToken token) {
|
||||
if (token == null) {
|
||||
@@ -138,12 +160,12 @@ public class XmlEmmetParser extends EmmetParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<Couple<String>> attrList = parseSelectors();
|
||||
if (mustHaveSelector && attrList.size() == 0) {
|
||||
final Map<String, String> attributes = parseSelectors();
|
||||
if (mustHaveSelector && attributes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TemplateToken templateToken = new TemplateToken(templateKey, attrList);
|
||||
final TemplateToken templateToken = new TemplateToken(templateKey, attributes);
|
||||
if (!setTemplate(templateToken, template)) {
|
||||
return null;
|
||||
}
|
||||
@@ -203,16 +225,16 @@ public class XmlEmmetParser extends EmmetParser {
|
||||
loremWordsCount = group == null || group.isEmpty() ? DEFAULT_LOREM_LENGTH : Integer.parseInt(group);
|
||||
}
|
||||
|
||||
final List<Couple<String>> attrList = parseSelectors();
|
||||
final Map<String, String> attributes = parseSelectors();
|
||||
ZenCodingToken token = getToken();
|
||||
boolean isRepeating = token instanceof OperationToken && ((OperationToken)token).getSign() == '*';
|
||||
if (!attrList.isEmpty() || isRepeating) {
|
||||
if (!attributes.isEmpty() || isRepeating) {
|
||||
String wrapTag = suggestTagName();
|
||||
TemplateImpl template = myCallback.findApplicableTemplate(templateKey);
|
||||
if (template == null && !ZenCodingUtil.isXML11ValidQName(templateKey)) {
|
||||
return null;
|
||||
}
|
||||
final TemplateToken templateToken = new TemplateToken(wrapTag, attrList);
|
||||
final TemplateToken templateToken = new TemplateToken(wrapTag, attributes);
|
||||
if (!setTemplate(templateToken, template)) {
|
||||
return null;
|
||||
}
|
||||
@@ -246,55 +268,25 @@ public class XmlEmmetParser extends EmmetParser {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
private List<Couple<String>> parseSelectors() {
|
||||
final List<Couple<String>> result = new ArrayList<Couple<String>>();
|
||||
|
||||
int classAttrPosition = -1;
|
||||
int idAttrPosition = -1;
|
||||
|
||||
final StringBuilder classAttrBuilder = new StringBuilder();
|
||||
final StringBuilder idAttrBuilder = new StringBuilder();
|
||||
|
||||
while (true) {
|
||||
final List<Couple<String>> attrList = parseSelector();
|
||||
if (attrList == null) {
|
||||
if (classAttrPosition != -1) {
|
||||
result.set(classAttrPosition, Couple.of(getClassAttributeName(), classAttrBuilder.toString()));
|
||||
}
|
||||
if (idAttrPosition != -1) {
|
||||
result.set(idAttrPosition, Couple.of(HtmlUtil.ID_ATTRIBUTE_NAME, idAttrBuilder.toString()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, String> parseSelectors() {
|
||||
final Map<String, String> result = ContainerUtil.newLinkedHashMap();
|
||||
List<Couple<String>> attrList = parseSelector();
|
||||
while (attrList != null) {
|
||||
for (Couple<String> attr : attrList) {
|
||||
if (getClassAttributeName().equals(attr.first)) {
|
||||
if (classAttrBuilder.length() > 0) {
|
||||
classAttrBuilder.append(' ');
|
||||
}
|
||||
classAttrBuilder.append(attr.second);
|
||||
if (classAttrPosition == -1) {
|
||||
classAttrPosition = result.size();
|
||||
result.add(attr);
|
||||
}
|
||||
result.put(getClassAttributeName(), (StringUtil.notNullize(result.get(getClassAttributeName())) + " " + attr.second).trim());
|
||||
}
|
||||
else if (HtmlUtil.ID_ATTRIBUTE_NAME.equals(attr.first)) {
|
||||
if (idAttrBuilder.length() > 0) {
|
||||
idAttrBuilder.append(' ');
|
||||
}
|
||||
idAttrBuilder.append(attr.second);
|
||||
if (idAttrPosition == -1) {
|
||||
idAttrPosition = result.size();
|
||||
result.add(attr);
|
||||
}
|
||||
result.put(HtmlUtil.ID_ATTRIBUTE_NAME, (StringUtil.notNullize(result.get(HtmlUtil.ID_ATTRIBUTE_NAME)) + " " + attr.second).trim());
|
||||
}
|
||||
else {
|
||||
result.add(attr);
|
||||
result.put(attr.first, attr.second);
|
||||
}
|
||||
}
|
||||
attrList = parseSelector();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -349,46 +341,57 @@ public class XmlEmmetParser extends EmmetParser {
|
||||
|
||||
@Nullable
|
||||
private Couple<String> parseAttribute() {
|
||||
ZenCodingToken token = getToken();
|
||||
if (!(token instanceof IdentifierToken)) {
|
||||
return null;
|
||||
String attributeName = getAttributeNameByToken(getToken());
|
||||
|
||||
if (attributeName != null && !attributeName.isEmpty()) {
|
||||
if (nextToken(1) == ZenCodingTokens.DOT) {
|
||||
if (isEndOfAttribute(nextToken(2))) {
|
||||
// boolean attribute
|
||||
advance(); //id
|
||||
advance(); // dot
|
||||
return Couple.of(attributeName, BOOLEAN_ATTRIBUTE_VALUE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// attribute with value
|
||||
advance();
|
||||
if (getToken() == ZenCodingTokens.EQ) {
|
||||
advance();
|
||||
return Couple.of(attributeName, parseAttributeValue());
|
||||
}
|
||||
else {
|
||||
return Couple.of(attributeName, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String name = ((IdentifierToken)token).getText();
|
||||
|
||||
if (name.isEmpty()) {
|
||||
return null;
|
||||
final String impliedValue = parseAttributeValue();
|
||||
if (!impliedValue.isEmpty()) {
|
||||
// implied attribute
|
||||
return Couple.of(DEFAULT_ATTRIBUTE_NAME, impliedValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final XmlTag tag = XmlElementFactory.getInstance(myCallback.getProject()).createTagFromText("<tag " + name + "=''/>");
|
||||
XmlAttribute[] attributes = tag.getAttributes();
|
||||
if (attributes.length == 1) {
|
||||
name = attributes[0].getName();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
advance();
|
||||
token = getToken();
|
||||
if (token != ZenCodingTokens.EQ) {
|
||||
return Couple.of(name, "");
|
||||
}
|
||||
|
||||
advance();
|
||||
@NotNull
|
||||
private String parseAttributeValue() {
|
||||
ZenCodingToken token;
|
||||
final StringBuilder attrValueBuilder = new StringBuilder();
|
||||
String value;
|
||||
do {
|
||||
token = getToken();
|
||||
value = getAttributeValueByToken(token);
|
||||
attrValueBuilder.append(value);
|
||||
if (token != null && token != ZenCodingTokens.CLOSING_SQ_BRACKET
|
||||
&& token != ZenCodingTokens.SPACE && token != ZenCodingTokens.COMMA) {
|
||||
if (!isEndOfAttribute(token)) {
|
||||
advance();
|
||||
}
|
||||
}
|
||||
while (token != null && token != ZenCodingTokens.CLOSING_SQ_BRACKET
|
||||
&& token != ZenCodingTokens.SPACE && token != ZenCodingTokens.COMMA);
|
||||
return Couple.of(name, attrValueBuilder.toString());
|
||||
while (!isEndOfAttribute(token));
|
||||
return attrValueBuilder.toString();
|
||||
}
|
||||
|
||||
private static boolean isEndOfAttribute(@Nullable ZenCodingToken nextToken) {
|
||||
return nextToken == null || nextToken == ZenCodingTokens.SPACE || nextToken == ZenCodingTokens.CLOSING_SQ_BRACKET
|
||||
|| nextToken == ZenCodingTokens.COMMA;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.JBPopupListener;
|
||||
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -67,9 +66,6 @@ import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class ZenCodingTemplate extends CustomLiveTemplateBase {
|
||||
public static final char MARKER = '\0';
|
||||
private static final String EMMET_RECENT_WRAP_ABBREVIATIONS_KEY = "emmet.recent.wrap.abbreviations";
|
||||
@@ -302,11 +298,9 @@ public class ZenCodingTemplate extends CustomLiveTemplateBase {
|
||||
if (node instanceof TemplateNode) {
|
||||
final TemplateToken token = ((TemplateNode)node).getTemplateToken();
|
||||
if (token != null) {
|
||||
final List<Couple<String>> attributes = token.getAttribute2Value();
|
||||
final Couple<String> singleAttribute = ContainerUtil.getFirstItem(attributes);
|
||||
if (singleAttribute == null || HtmlUtil.CLASS_ATTRIBUTE_NAME.equalsIgnoreCase(singleAttribute.first) && StringUtil.isEmpty(singleAttribute.second)) {
|
||||
return true;
|
||||
}
|
||||
final Map<String, String> attributes = token.getAttributes();
|
||||
return attributes.isEmpty() ||
|
||||
attributes.containsKey(HtmlUtil.CLASS_ATTRIBUTE_NAME) && StringUtil.isEmpty(attributes.get(HtmlUtil.CLASS_ATTRIBUTE_NAME));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
|
||||
import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -30,10 +29,7 @@ import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
@@ -43,9 +39,6 @@ import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Lists.newLinkedList;
|
||||
|
||||
/**
|
||||
* User: zolotov
|
||||
* Date: 2/4/13
|
||||
* <p/>
|
||||
* Bem filter for emmet support.
|
||||
* See the original source code here: https://github.com/emmetio/emmet/blob/master/javascript/filters/bem.js
|
||||
* And documentation here: http://docs.emmet.io/filters/bem/
|
||||
@@ -115,10 +108,10 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
@NotNull
|
||||
@Override
|
||||
public GenerationNode filterNode(@NotNull final GenerationNode node) {
|
||||
final List<Couple<String>> attribute2Value = node.getTemplateToken().getAttribute2Value();
|
||||
Couple<String> classNamePair = getClassPair(attribute2Value);
|
||||
if (classNamePair != null) {
|
||||
Iterable<String> classNames = extractClasses(classNamePair.second);
|
||||
final Map<String, String> attributes = node.getTemplateToken().getAttributes();
|
||||
String classValue = attributes.get(HtmlUtil.CLASS_ATTRIBUTE_NAME);
|
||||
if (classValue != null) {
|
||||
Iterable<String> classNames = extractClasses(classValue);
|
||||
BEM_STATE.set(node, new BemState(suggestBlockName(classNames), null, null));
|
||||
final Set<String> newClassNames = ImmutableSet.copyOf(concat(transform(classNames, new Function<String, Iterable<String>>() {
|
||||
@Override
|
||||
@@ -126,7 +119,7 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
return processClassName(className, node);
|
||||
}
|
||||
})));
|
||||
attribute2Value.add(Couple.of(HtmlUtil.CLASS_ATTRIBUTE_NAME, CLASS_NAME_JOINER.join(newClassNames)));
|
||||
attributes.put(HtmlUtil.CLASS_ATTRIBUTE_NAME, CLASS_NAME_JOINER.join(newClassNames));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -278,23 +271,6 @@ public class BemEmmetFilter extends ZenCodingFilter {
|
||||
return find(classNames, BLOCK_NAME_PREDICATE, find(classNames, STARTS_WITH_LETTER, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve pair "class" => classAttributeValue from node attributeList
|
||||
*
|
||||
* @param attribute2Value node's attributes
|
||||
* @return pointer to pair
|
||||
*/
|
||||
@Nullable
|
||||
private static Couple<String> getClassPair(@NotNull List<Couple<String>> attribute2Value) {
|
||||
for (int i = 0; i < attribute2Value.size(); i++) {
|
||||
Couple<String> pair = attribute2Value.get(i);
|
||||
if (HtmlUtil.CLASS_ATTRIBUTE_NAME.equals(pair.first) && !isNullOrEmpty(pair.second)) {
|
||||
return attribute2Value.remove(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class BemState {
|
||||
@Nullable private String block;
|
||||
@Nullable private String element;
|
||||
|
||||
+2
-8
@@ -21,7 +21,6 @@ import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGeneratorI
|
||||
import com.intellij.codeInsight.template.emmet.nodes.GenerationNode;
|
||||
import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlAttribute;
|
||||
import com.intellij.psi.xml.XmlDocument;
|
||||
@@ -29,9 +28,6 @@ import com.intellij.psi.xml.XmlTag;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class XslZenCodingFilter extends ZenCodingFilter {
|
||||
private final XmlZenCodingGenerator myDelegate = new XmlZenCodingGeneratorImpl();
|
||||
@NonNls private static final String SELECT_ATTR_NAME = "select";
|
||||
@@ -45,10 +41,8 @@ public class XslZenCodingFilter extends ZenCodingFilter {
|
||||
if (document != null) {
|
||||
final XmlTag tag = document.getRootTag();
|
||||
if (tag != null) {
|
||||
for (Couple<String> pair : token.getAttribute2Value()) {
|
||||
if (SELECT_ATTR_NAME.equals(pair.first)) {
|
||||
return node;
|
||||
}
|
||||
if (token.getAttributes().containsKey(SELECT_ATTR_NAME)) {
|
||||
return node;
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
|
||||
+8
-12
@@ -22,7 +22,6 @@ import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.diagnostic.AttachmentFactory;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -36,12 +35,8 @@ import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public abstract class XmlZenCodingGenerator extends ZenCodingGenerator {
|
||||
@Override
|
||||
public TemplateImpl generateTemplate(@NotNull TemplateToken token, boolean hasChildren, @NotNull PsiElement context) {
|
||||
@@ -70,19 +65,19 @@ public abstract class XmlZenCodingGenerator extends ZenCodingGenerator {
|
||||
if (document != null) {
|
||||
XmlTag tag = document.getRootTag();
|
||||
if (tag != null) {
|
||||
return toString(tag, token.getAttribute2Value(), hasChildren, context);
|
||||
return toString(tag, token.getAttributes(), hasChildren, context);
|
||||
}
|
||||
}
|
||||
return file.getText();
|
||||
}
|
||||
|
||||
public abstract String toString(@NotNull XmlTag tag,
|
||||
@NotNull List<Couple<String>> attribute2Value,
|
||||
@NotNull Map<String, String> attributes,
|
||||
boolean hasChildren,
|
||||
@NotNull PsiElement context);
|
||||
|
||||
@NotNull
|
||||
public abstract String buildAttributesString(@NotNull List<Couple<String>> attribute2value,
|
||||
public abstract String buildAttributesString(@NotNull Map<String, String> attribute2value,
|
||||
boolean hasChildren,
|
||||
int numberInIteration,
|
||||
int totalIterations, @Nullable String surroundedText);
|
||||
@@ -111,12 +106,13 @@ public abstract class XmlZenCodingGenerator extends ZenCodingGenerator {
|
||||
break;
|
||||
}
|
||||
}
|
||||
prevVisibleLeaf = PsiTreeUtil.prevVisibleLeaf(prevVisibleLeaf);
|
||||
prevVisibleLeaf = PsiTreeUtil.prevVisibleLeaf(prevVisibleLeaf);
|
||||
}
|
||||
|
||||
if (startOffset < 0 || currentOffset > documentText.length() || currentOffset < startOffset) {
|
||||
Logger.getInstance(getClass()).error("Error while calculating emmet abbreviation. Offset: " + currentOffset + "; Start: " + startOffset,
|
||||
AttachmentFactory.createAttachment(editor.getDocument()));
|
||||
Logger.getInstance(getClass())
|
||||
.error("Error while calculating emmet abbreviation. Offset: " + currentOffset + "; Start: " + startOffset,
|
||||
AttachmentFactory.createAttachment(editor.getDocument()));
|
||||
return null;
|
||||
}
|
||||
String key = computeKey(documentText.subSequence(startOffset, currentOffset));
|
||||
|
||||
+8
-12
@@ -29,7 +29,6 @@ import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.options.UnnamedConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.xml.XmlChildRole;
|
||||
@@ -38,8 +37,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
@@ -54,7 +53,7 @@ public class XmlZenCodingGeneratorImpl extends XmlZenCodingGenerator {
|
||||
@Override
|
||||
@NotNull
|
||||
public String toString(@NotNull XmlTag tag,
|
||||
@NotNull List<Couple<String>> attribute2Value,
|
||||
@NotNull Map<String, String> attributes,
|
||||
boolean hasChildren,
|
||||
@NotNull PsiElement context) {
|
||||
FileType fileType = context.getContainingFile().getFileType();
|
||||
@@ -66,21 +65,18 @@ public class XmlZenCodingGeneratorImpl extends XmlZenCodingGenerator {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildAttributesString(@NotNull List<Couple<String>> attribute2value,
|
||||
public String buildAttributesString(@NotNull Map<String, String> attributes,
|
||||
boolean hasChildren,
|
||||
int numberInIteration,
|
||||
int totalIterations, @Nullable String surroundedText) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Iterator<Couple<String>> it = attribute2value.iterator(); it.hasNext();) {
|
||||
Couple<String> pair = it.next();
|
||||
String name = pair.first;
|
||||
String value = ZenCodingUtil.getValue(pair.second, numberInIteration, totalIterations, surroundedText);
|
||||
for (Map.Entry<String, String> entry : attributes.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = ZenCodingUtil.getValue(entry.getValue(), numberInIteration, totalIterations, surroundedText);
|
||||
result.append(getAttributeString(name, value));
|
||||
if (it.hasNext()) {
|
||||
result.append(' ');
|
||||
}
|
||||
result.append(' ');
|
||||
}
|
||||
return result.toString();
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
package com.intellij.codeInsight.template.emmet.nodes;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.intellij.application.options.emmet.EmmetOptions;
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.LiveTemplateBuilder;
|
||||
import com.intellij.codeInsight.template.emmet.XmlEmmetParser;
|
||||
import com.intellij.codeInsight.template.emmet.ZenCodingUtil;
|
||||
import com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter;
|
||||
import com.intellij.codeInsight.template.emmet.filters.ZenCodingFilter;
|
||||
@@ -33,7 +35,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -46,6 +48,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
@@ -187,9 +190,9 @@ public class GenerationNode extends UserDataHolderBase {
|
||||
Map<String, String> predefinedValues;
|
||||
if (myTemplateToken instanceof TemplateToken && generator instanceof XmlZenCodingGenerator) {
|
||||
TemplateToken xmlTemplateToken = myTemplateToken;
|
||||
List<Couple<String>> attr2value = new ArrayList<Couple<String>>(xmlTemplateToken.getAttribute2Value());
|
||||
parentTemplate = invokeXmlTemplate(xmlTemplateToken, callback, generator, hasChildren, attr2value);
|
||||
predefinedValues = buildPredefinedValues(attr2value, (XmlZenCodingGenerator)generator, hasChildren);
|
||||
Map<String, String> attributes = xmlTemplateToken.getAttributes();
|
||||
parentTemplate = invokeXmlTemplate(xmlTemplateToken, callback, generator, hasChildren, attributes);
|
||||
predefinedValues = buildPredefinedValues(attributes, (XmlZenCodingGenerator)generator, hasChildren);
|
||||
}
|
||||
else {
|
||||
parentTemplate = invokeTemplate(myTemplateToken, hasChildren, callback, generator);
|
||||
@@ -265,7 +268,7 @@ public class GenerationNode extends UserDataHolderBase {
|
||||
CustomTemplateCallback callback,
|
||||
@Nullable ZenCodingGenerator generator,
|
||||
final boolean hasChildren,
|
||||
final List<Couple<String>> attr2value) {
|
||||
final Map<String, String> attributes) {
|
||||
/*assert generator == null || generator instanceof XmlZenCodingGenerator :
|
||||
"The generator cannot process TemplateToken because it doesn't inherit XmlZenCodingGenerator";*/
|
||||
|
||||
@@ -274,17 +277,17 @@ public class GenerationNode extends UserDataHolderBase {
|
||||
|
||||
final XmlFile xmlFile = token.getFile();
|
||||
PsiFileFactory fileFactory = PsiFileFactory.getInstance(xmlFile.getProject());
|
||||
XmlFile dummyFile = (XmlFile)fileFactory.createFileFromText("dummy.xml", StdFileTypes.XML, xmlFile.getText());
|
||||
XmlFile dummyFile = (XmlFile)fileFactory.createFileFromText("dummy.html", StdFileTypes.HTML, xmlFile.getText());
|
||||
final XmlTag tag = dummyFile.getRootTag();
|
||||
if (tag != null) {
|
||||
for (Couple<String> pair : attr2value) {
|
||||
if (Strings.isNullOrEmpty(pair.second)) {
|
||||
template.addVariable(prepareVariableName(pair.first), "", "", true);
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
if (Strings.isNullOrEmpty(attribute.getValue())) {
|
||||
template.addVariable(prepareVariableName(attribute.getKey()), "", "", true);
|
||||
}
|
||||
}
|
||||
XmlTag tag1 = hasChildren ? expandEmptyTagIfNecessary(tag) : tag;
|
||||
setAttributeValues(tag1, attr2value);
|
||||
XmlFile physicalFile = (XmlFile)fileFactory.createFileFromText("dummy.xml", StdFileTypes.XML, tag1.getContainingFile().getText(),
|
||||
setAttributeValues(tag1, attributes, callback);
|
||||
XmlFile physicalFile = (XmlFile)fileFactory.createFileFromText("dummy.html", StdFileTypes.HTML, tag1.getContainingFile().getText(),
|
||||
LocalTimeCounter.currentTime(), true);
|
||||
VirtualFile vFile = physicalFile.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
@@ -381,44 +384,153 @@ public class GenerationNode extends UserDataHolderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Map<String, String> buildPredefinedValues(List<Couple<String>> attribute2value,
|
||||
private Map<String, String> buildPredefinedValues(@NotNull Map<String, String> attributes,
|
||||
@Nullable XmlZenCodingGenerator generator,
|
||||
boolean hasChildren) {
|
||||
if (generator == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
for (Couple<String> pair : attribute2value) {
|
||||
if (ZenCodingUtil.containsSurroundedTextMarker(pair.second)) {
|
||||
for (String value : attributes.values()) {
|
||||
if (ZenCodingUtil.containsSurroundedTextMarker(value)) {
|
||||
myContainsSurroundedTextMarker = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String attributes = generator.buildAttributesString(attribute2value, hasChildren, myNumberInIteration, myTotalIterations, mySurroundedText);
|
||||
attributes = attributes.length() > 0 ? ' ' + attributes : null;
|
||||
String attributesString = generator.buildAttributesString(attributes, hasChildren, myNumberInIteration, myTotalIterations, mySurroundedText);
|
||||
attributesString = attributesString.length() > 0 ? ' ' + attributesString : null;
|
||||
Map<String, String> predefinedValues = null;
|
||||
if (attributes != null) {
|
||||
if (attributesString != null) {
|
||||
predefinedValues = new HashMap<String, String>();
|
||||
predefinedValues.put(TemplateToken.ATTRS, attributes);
|
||||
predefinedValues.put(TemplateToken.ATTRS, attributesString);
|
||||
}
|
||||
return predefinedValues;
|
||||
}
|
||||
|
||||
private void setAttributeValues(XmlTag tag, List<Couple<String>> attr2value) {
|
||||
for (Iterator<Couple<String>> iterator = attr2value.iterator(); iterator.hasNext();) {
|
||||
Couple<String> pair = iterator.next();
|
||||
if (tag.getAttribute(pair.first) != null) {
|
||||
if (ZenCodingUtil.containsSurroundedTextMarker(pair.second)) {
|
||||
myContainsSurroundedTextMarker = true;
|
||||
private void setAttributeValues(@NotNull XmlTag tag, @NotNull final Map<String, String> attributes, CustomTemplateCallback callback) {
|
||||
final String defaultAttributeValue = attributes.get(XmlEmmetParser.DEFAULT_ATTRIBUTE_NAME);
|
||||
if (defaultAttributeValue != null) {
|
||||
attributes.remove(XmlEmmetParser.DEFAULT_ATTRIBUTE_NAME);
|
||||
|
||||
// exclude user defined attributes
|
||||
final List<XmlAttribute> xmlAttributes = ContainerUtil.filter(tag.getAttributes(), new Condition<XmlAttribute>() {
|
||||
@Override
|
||||
public boolean value(XmlAttribute attribute) {
|
||||
return !attributes.containsKey(attribute.getLocalName());
|
||||
}
|
||||
});
|
||||
XmlAttribute defaultAttribute = findDefaultAttribute(xmlAttributes);
|
||||
if (defaultAttribute == null) {
|
||||
defaultAttribute = findImpliedAttribute(xmlAttributes);
|
||||
}
|
||||
if (defaultAttribute == null) {
|
||||
defaultAttribute = findEmptyAttribute(xmlAttributes);
|
||||
}
|
||||
if (defaultAttribute != null) {
|
||||
String attributeName = defaultAttribute.getName();
|
||||
if (attributeName.length() > 1) {
|
||||
if (isImpliedAttribute(attributeName) || isDefaultAttribute(attributeName)) {
|
||||
defaultAttribute.setName(attributeName.substring(1));
|
||||
}
|
||||
final String oldValue = defaultAttribute.getValue();
|
||||
if (oldValue != null && StringUtil.containsChar(oldValue, '|')) {
|
||||
defaultAttribute.setValue(StringUtil.replace(oldValue, "|", defaultAttributeValue));
|
||||
}
|
||||
else {
|
||||
defaultAttribute.setValue(defaultAttributeValue);
|
||||
}
|
||||
}
|
||||
tag.setAttribute(pair.first,
|
||||
Strings.isNullOrEmpty(pair.second)
|
||||
? "$" + prepareVariableName(pair.first) + "$"
|
||||
: ZenCodingUtil.getValue(pair.second, myNumberInIteration, myTotalIterations, mySurroundedText));
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
final String attributeName = attribute.getKey();
|
||||
final XmlAttribute xmlAttribute = tag.getAttribute(attributeName);
|
||||
if (xmlAttribute != null) {
|
||||
final String attributeValue = attribute.getValue();
|
||||
|
||||
if (ZenCodingUtil.containsSurroundedTextMarker(attributeValue)) {
|
||||
myContainsSurroundedTextMarker = true;
|
||||
}
|
||||
|
||||
final EmmetOptions emmetOptions = EmmetOptions.getInstance();
|
||||
if (isBooleanAttribute(attributeName, attributeValue)) {
|
||||
if (emmetOptions.isCompactBooleanAllowed() && ZenCodingUtil.isHtml(callback)) {
|
||||
final XmlAttributeValue valueElement = xmlAttribute.getValueElement();
|
||||
if (valueElement != null) {
|
||||
final PsiElement prevSibling = valueElement.getPrevSibling();
|
||||
if (prevSibling != null && prevSibling.textMatches("=")) {
|
||||
xmlAttribute.deleteChildRange(prevSibling, valueElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tag.setAttribute(attributeName, attributeName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tag.setAttribute(attributeName,
|
||||
Strings.isNullOrEmpty(attributeValue)
|
||||
? "$" + prepareVariableName(attributeName) + "$"
|
||||
: ZenCodingUtil.getValue(attributeValue, myNumberInIteration, myTotalIterations, mySurroundedText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all implicit and default attributes
|
||||
for (XmlAttribute xmlAttribute : tag.getAttributes()) {
|
||||
final String xmlAttributeLocalName = xmlAttribute.getLocalName();
|
||||
if (isImpliedAttribute(xmlAttributeLocalName) || isDefaultAttribute(xmlAttributeLocalName)) {
|
||||
xmlAttribute.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBooleanAttribute(String name, String value) {
|
||||
if (value.equals(XmlEmmetParser.BOOLEAN_ATTRIBUTE_VALUE)) {
|
||||
return true;
|
||||
}
|
||||
return Strings.isNullOrEmpty(value) && EmmetOptions.getInstance().getBooleanAttributes().contains(name.toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
private static boolean isDefaultAttribute(String xmlAttributeLocalName) {
|
||||
return StringUtil.startsWithChar(xmlAttributeLocalName, '@');
|
||||
}
|
||||
|
||||
private static boolean isImpliedAttribute(String xmlAttributeLocalName) {
|
||||
return StringUtil.startsWithChar(xmlAttributeLocalName, '!');
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static XmlAttribute findDefaultAttribute(@NotNull List<XmlAttribute> attributes) {
|
||||
for (XmlAttribute attribute : attributes) {
|
||||
if (isDefaultAttribute(attribute.getLocalName())) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static XmlAttribute findImpliedAttribute(@NotNull List<XmlAttribute> attributes) {
|
||||
for (XmlAttribute attribute : attributes) {
|
||||
if (isImpliedAttribute(attribute.getLocalName())) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static XmlAttribute findEmptyAttribute(@NotNull List<XmlAttribute> attributes) {
|
||||
for (XmlAttribute attribute : attributes) {
|
||||
final String attributeValue = attribute.getValue();
|
||||
if (StringUtil.isEmpty(attributeValue) || StringUtil.startsWithChar(attributeValue, '$') && StringUtil.endsWithChar(attributeValue, '$')) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isNewLineBefore(CharSequence text, int offset) {
|
||||
|
||||
@@ -19,16 +19,12 @@ import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.emmet.generators.LoremGenerator;
|
||||
import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class LoremNode extends ZenCodingNode {
|
||||
private final int myWordsCount;
|
||||
private final LoremGenerator myLoremGenerator;
|
||||
@@ -46,7 +42,7 @@ public class LoremNode extends ZenCodingNode {
|
||||
boolean insertSurroundedTextAtTheEnd, GenerationNode parent) {
|
||||
|
||||
|
||||
final TemplateToken templateToken = new TemplateToken("", Collections.<Couple<String>>emptyList());
|
||||
final TemplateToken templateToken = new TemplateToken("");
|
||||
final TemplateImpl template = new TemplateImpl("", myLoremGenerator.generate(myWordsCount, numberInIteration <= 0), "");
|
||||
templateToken.setTemplate(template, callback);
|
||||
final GenerationNode node = new GenerationNode(templateToken, numberInIteration,
|
||||
|
||||
@@ -15,25 +15,21 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.template.emmet.nodes;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.emmet.ZenCodingUtil;
|
||||
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
|
||||
import com.intellij.codeInsight.template.emmet.tokens.TemplateToken;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class TemplateNode extends ZenCodingNode {
|
||||
private static final Joiner JOINER = Joiner.on(",");
|
||||
private final TemplateToken myTemplateToken;
|
||||
@Nullable private final ZenCodingGenerator myGenerator;
|
||||
|
||||
@@ -60,7 +56,7 @@ public class TemplateNode extends ZenCodingNode {
|
||||
String templateKey = templateToken.getKey();
|
||||
if (myGenerator != null && StringUtil.containsChar(templateKey, '$') && callback.findApplicableTemplate(templateKey) == null) {
|
||||
String newTemplateKey = ZenCodingUtil.replaceMarkers(templateKey, numberInIteration, totalIterations, surroundedText);
|
||||
TemplateToken newTemplateToken = new TemplateToken(newTemplateKey, templateToken.getAttribute2Value());
|
||||
TemplateToken newTemplateToken = new TemplateToken(newTemplateKey, templateToken.getAttributes());
|
||||
TemplateImpl template = myGenerator.createTemplateByKey(newTemplateKey);
|
||||
if (template != null) {
|
||||
template.setDeactivated(true);
|
||||
@@ -71,15 +67,15 @@ public class TemplateNode extends ZenCodingNode {
|
||||
|
||||
GenerationNode node = new GenerationNode(templateToken, numberInIteration, totalIterations,
|
||||
surroundedText, insertSurroundedTextAtTheEnd, parent);
|
||||
return Arrays.asList(node);
|
||||
return Collections.singletonList(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String result = myTemplateToken.getKey();
|
||||
List<Couple<String>> attributes = myTemplateToken.getAttribute2Value();
|
||||
Map<String, String> attributes = myTemplateToken.getAttributes();
|
||||
if (!attributes.isEmpty()) {
|
||||
result += "[" + JOINER.join(myTemplateToken.getAttribute2Value()) + "]";
|
||||
result += ContainerUtil.toString(attributes);
|
||||
}
|
||||
return "Template(" + result + ")";
|
||||
}
|
||||
@@ -89,8 +85,8 @@ public class TemplateNode extends ZenCodingNode {
|
||||
TemplateImpl template = myTemplateToken.getTemplate();
|
||||
if (template != null) {
|
||||
int result = template.getTemplateText().length();
|
||||
for (Couple<String> attribute : myTemplateToken.getAttribute2Value()) {
|
||||
result += attribute.first.length() + attribute.second.length() + 4; //plus space, eq, quotes
|
||||
for (Map.Entry<String, String> attribute : myTemplateToken.getAttributes().entrySet()) {
|
||||
result += attribute.getKey().length() + attribute.getValue().length() + 4; //plus space, eq, quotes
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
package com.intellij.codeInsight.template.emmet.tokens;
|
||||
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.emmet.XmlEmmetParser;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.openapi.command.undo.UndoConstants;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.XmlElementFactory;
|
||||
@@ -28,36 +28,34 @@ import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.LocalTimeCounter;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class TemplateToken extends ZenCodingToken {
|
||||
public static final String ATTRS = "ATTRS";
|
||||
public final static TemplateToken EMPTY_TEMPLATE_TOKEN = new TemplateToken("", new ArrayList<Couple<String>>());
|
||||
public final static TemplateToken EMPTY_TEMPLATE_TOKEN = new TemplateToken("", Collections.<String, String>emptyMap());
|
||||
|
||||
private final String myKey;
|
||||
@NotNull private final String myKey;
|
||||
private TemplateImpl myTemplate;
|
||||
private final List<Couple<String>> myAttribute2Value;
|
||||
@NotNull private final Map<String, String> myAttributes;
|
||||
private XmlFile myFile;
|
||||
|
||||
public TemplateToken(String key) {
|
||||
this(key, new ArrayList<Couple<String>>());
|
||||
public TemplateToken(@NotNull String key) {
|
||||
this(key, Collections.<String, String>emptyMap());
|
||||
}
|
||||
|
||||
public TemplateToken(String key, List<Couple<String>> attribute2value) {
|
||||
public TemplateToken(@NotNull String key, @NotNull Map<String, String> attribute2value) {
|
||||
myKey = key;
|
||||
myAttribute2Value = attribute2value;
|
||||
myAttributes = attribute2value;
|
||||
}
|
||||
|
||||
public List<Couple<String>> getAttribute2Value() {
|
||||
return myAttribute2Value;
|
||||
@NotNull
|
||||
public Map<String, String> getAttributes() {
|
||||
return myAttributes;
|
||||
}
|
||||
|
||||
public XmlFile getFile() {
|
||||
@@ -68,23 +66,24 @@ public class TemplateToken extends ZenCodingToken {
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getKey() {
|
||||
return myKey;
|
||||
}
|
||||
|
||||
public boolean setTemplate(TemplateImpl template, CustomTemplateCallback callback) {
|
||||
public boolean setTemplate(@NotNull TemplateImpl template, @NotNull CustomTemplateCallback callback) {
|
||||
myTemplate = template;
|
||||
final XmlFile xmlFile = parseXmlFileInTemplate(template, callback, getAttribute2Value());
|
||||
final XmlFile xmlFile = parseXmlFileInTemplate(template, callback, getAttributes());
|
||||
setFile(xmlFile);
|
||||
final XmlTag tag = xmlFile.getRootTag();
|
||||
if (getAttribute2Value().size() > 0 && tag == null) {
|
||||
if (!getAttributes().isEmpty() && tag == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static boolean containsAttrsVar(TemplateImpl template) {
|
||||
private static boolean containsAttrsVar(@NotNull TemplateImpl template) {
|
||||
for (int i = 0; i < template.getVariableCount(); i++) {
|
||||
String varName = template.getVariableNameAt(i);
|
||||
if (ATTRS.equals(varName)) {
|
||||
@@ -95,9 +94,8 @@ public class TemplateToken extends ZenCodingToken {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static XmlFile parseXmlFileInTemplate(TemplateImpl template,
|
||||
CustomTemplateCallback callback,
|
||||
List<Couple<String>> attributes) {
|
||||
private static XmlFile parseXmlFileInTemplate(@NotNull TemplateImpl template, @NotNull CustomTemplateCallback callback,
|
||||
@NotNull Map<String, String> attributes) {
|
||||
XmlTag dummyRootTag = null;
|
||||
String templateString = template.getString();
|
||||
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(callback.getProject());
|
||||
@@ -110,7 +108,8 @@ public class TemplateToken extends ZenCodingToken {
|
||||
}
|
||||
|
||||
templateString = dummyRootTag != null ? dummyRootTag.getContainingFile().getText() : templateString;
|
||||
XmlFile xmlFile = (XmlFile)psiFileFactory.createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), true);
|
||||
XmlFile xmlFile =
|
||||
(XmlFile)psiFileFactory.createFileFromText("dummy.xml", StdFileTypes.XML, templateString, LocalTimeCounter.currentTime(), true);
|
||||
VirtualFile vFile = xmlFile.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
|
||||
@@ -119,22 +118,22 @@ public class TemplateToken extends ZenCodingToken {
|
||||
}
|
||||
|
||||
|
||||
private static void addMissingAttributes(XmlTag tag, List<Couple<String>> value) {
|
||||
List<Couple<String>> attr2value = new ArrayList<Couple<String>>(value);
|
||||
for (Iterator<Couple<String>> iterator = attr2value.iterator(); iterator.hasNext(); ) {
|
||||
Couple<String> pair = iterator.next();
|
||||
if (tag.getAttribute(pair.first) != null) {
|
||||
iterator.remove();
|
||||
private static void addMissingAttributes(@NotNull XmlTag tag, @NotNull Map<String, String> attributes) {
|
||||
Map<String, String> missingAttributes = ContainerUtil.newLinkedHashMap();
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
if (!XmlEmmetParser.DEFAULT_ATTRIBUTE_NAME.equals(attribute.getKey()) && tag.getAttribute(attribute.getKey()) == null) {
|
||||
missingAttributes.put(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
}
|
||||
addAttributesBefore(tag, attr2value);
|
||||
addAttributesBefore(tag, missingAttributes);
|
||||
}
|
||||
|
||||
private static void addAttributesBefore(XmlTag tag, List<Couple<String>> attr2value) {
|
||||
|
||||
private static void addAttributesBefore(@NotNull XmlTag tag, @NotNull Map<String, String> attributes) {
|
||||
XmlAttribute firstAttribute = ArrayUtil.getFirstElement(tag.getAttributes());
|
||||
XmlElementFactory factory = XmlElementFactory.getInstance(tag.getProject());
|
||||
for (Couple<String> pair : attr2value) {
|
||||
XmlAttribute xmlAttribute = factory.createXmlAttribute(pair.first, "");
|
||||
for (String name : attributes.keySet()) {
|
||||
XmlAttribute xmlAttribute = factory.createXmlAttribute(name, "");
|
||||
if (firstAttribute != null) {
|
||||
tag.addBefore(xmlAttribute, firstAttribute);
|
||||
}
|
||||
@@ -149,6 +148,7 @@ public class TemplateToken extends ZenCodingToken {
|
||||
return myTemplate;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String toString() {
|
||||
return "TEMPLATE";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user