diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml index 7768ba914899..c26e94dd8ed7 100644 --- a/.idea/inspectionProfiles/idea_default.xml +++ b/.idea/inspectionProfiles/idea_default.xml @@ -670,6 +670,17 @@ + + + + + + + + + + + diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java index f57753ef7afc..154c7008f0b3 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -41,7 +41,6 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; @@ -62,19 +61,19 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon private final boolean myMake; private final boolean myIsRebuild; private final boolean myIsAnnotationProcessorsEnabled; - private boolean myRebuildRequested = false; + private boolean myRebuildRequested; private String myRebuildReason; private final Map myRootToModuleMap = new HashMap(); private final Map> myModuleToRootsMap = new HashMap>(); - private final Set myGeneratedTestRoots = new java.util.HashSet(); + private final Set myGeneratedTestRoots = new HashSet(); private final ProjectFileIndex myProjectFileIndex; // cached for performance reasons private final ProjectCompileScope myProjectCompileScope; private final long myStartCompilationStamp; private final UUID mySessionId = UUID.randomUUID(); - public CompileContextImpl(final Project project, - final CompilerTask compilerSession, - CompileScope compileScope, + public CompileContextImpl(@NotNull Project project, + @NotNull CompilerTask compilerSession, + @NotNull CompileScope compileScope, boolean isMake, boolean isRebuild) { myProject = project; myBuildSession = compilerSession; @@ -86,19 +85,18 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon myProjectCompileScope = new ProjectCompileScope(myProject); myIsAnnotationProcessorsEnabled = CompilerConfiguration.getInstance(project).isAnnotationProcessorsEnabled(); - if (compilerSession != null) { - final Object sessionId = ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.get(compileScope); - if (sessionId != null) { - // in case compilation is started as a part of some execution session, - // all compilation tasks should have the same sessionId in order for successive task not to clean messages - // from previous compilation tasks run within this execution session - compilerSession.setSessionId(sessionId); - } + final Object sessionId = ExecutionManagerImpl.EXECUTION_SESSION_ID_KEY.get(compileScope); + if (sessionId != null) { + // in case compilation is started as a part of some execution session, + // all compilation tasks should have the same sessionId in order for successive task not to clean messages + // from previous compilation tasks run within this execution session + compilerSession.setSessionId(sessionId); } final CompilerWorkspaceConfiguration workspaceConfig = CompilerWorkspaceConfiguration.getInstance(myProject); myShouldUpdateProblemsView = workspaceConfig.MAKE_PROJECT_ON_SAVE; } + @NotNull public CompilerTask getBuildSession() { return myBuildSession; } @@ -111,10 +109,13 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return myStartCompilationStamp; } + @Override + @NotNull public Project getProject() { return myProject; } + @Override public CompilerMessage[] getMessages(CompilerMessageCategory category) { Collection collection = myMessages.get(category); if (collection == null) { @@ -123,11 +124,13 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return collection.toArray(new CompilerMessage[collection.size()]); } + @Override public void addMessage(CompilerMessageCategory category, String message, String url, int lineNum, int columnNum) { final CompilerMessageImpl msg = new CompilerMessageImpl(myProject, category, message, findFileByUrl(url), lineNum, columnNum, null); addMessage(msg); } + @Override public void addMessage(CompilerMessageCategory category, String message, String url, int lineNum, int columnNum, Navigatable navigatable) { final CompilerMessageImpl msg = new CompilerMessageImpl(myProject, category, message, findFileByUrl(url), lineNum, columnNum, navigatable); @@ -147,6 +150,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return file; } + @Override public void addMessage(CompilerMessage msg) { if (ApplicationManager.getApplication().isUnitTestMode()) { LOG.info("addMessage: " + msg + " this=" + this); @@ -165,6 +169,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } } + @Override public int getMessageCount(CompilerMessageCategory category) { if (category != null) { Collection collection = myMessages.get(category); @@ -179,14 +184,17 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return count; } + @Override public CompileScope getCompileScope() { return myCompileScope; } + @Override public CompileScope getProjectCompileScope() { return myProjectCompileScope; } + @Override public void requestRebuildNextTime(String message) { if (!myRebuildRequested) { myRebuildRequested = true; @@ -194,19 +202,24 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon } } + @Override public boolean isRebuildRequested() { return myRebuildRequested; } + @Override @Nullable public String getRebuildReason() { return myRebuildReason; } + @Override + @NotNull public ProgressIndicator getProgressIndicator() { return myBuildSession.getIndicator(); } + @Override public Module getModuleByFile(VirtualFile file) { final Module module = myProjectFileIndex.getModuleForFile(file); if (module != null) { @@ -214,7 +227,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return module; } for (final VirtualFile root : myRootToModuleMap.keySet()) { - if (VfsUtil.isAncestor(root, file, false)) { + if (VfsUtilCore.isAncestor(root, file, false)) { final Module mod = myRootToModuleMap.get(root); if (mod != null) { LOG.assertTrue(!mod.isDisposed()); @@ -228,6 +241,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon private final Map myModuleToRootsCache = new HashMap(); + @Override public VirtualFile[] getSourceRoots(Module module) { VirtualFile[] cachedRoots = myModuleToRootsCache.get(module); if (cachedRoots != null) { @@ -265,48 +279,50 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon return true; } + @Override public VirtualFile getModuleOutputDirectory(Module module) { return CompilerPaths.getModuleOutputDirectory(module, false); } + @Override public VirtualFile getModuleOutputDirectoryForTests(Module module) { return CompilerPaths.getModuleOutputDirectory(module, true); } + @Override public boolean isMake() { return myMake; } + @Override public boolean isRebuild() { return myIsRebuild; } + @Override public boolean isAnnotationProcessorsEnabled() { return myIsAnnotationProcessorsEnabled; } + @Override public void addScope(final CompileScope additionalScope) { myCompileScope = new CompositeScope(myCompileScope, additionalScope); } + @Override public boolean isInTestSourceContent(@NotNull final VirtualFile fileOrDir) { if (myProjectFileIndex.isInTestSourceContent(fileOrDir)) { return true; } - if (VfsUtilCore.isUnder(fileOrDir, myGeneratedTestRoots)) { - return true; - } - return false; + return VfsUtilCore.isUnder(fileOrDir, myGeneratedTestRoots); } + @Override public boolean isInSourceContent(@NotNull final VirtualFile fileOrDir) { if (myProjectFileIndex.isInSourceContent(fileOrDir)) { return true; } - if (VfsUtilCore.isUnder(fileOrDir, myRootToModuleMap.keySet())) { - return true; - } - return false; + return VfsUtilCore.isUnder(fileOrDir, myRootToModuleMap.keySet()); } public UUID getSessionId() { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java index 065cd6baf03f..7d53f0aa24d9 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java @@ -18,6 +18,7 @@ package com.intellij.compiler.impl; import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.compiler.CompilerBundle; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -172,16 +173,17 @@ public class CompilerUtil { } public static void runInContext(CompileContext context, String title, ThrowableRunnable action) throws T { + ProgressIndicator indicator = context.getProgressIndicator(); if (title != null) { - context.getProgressIndicator().pushState(); - context.getProgressIndicator().setText(title); + indicator.pushState(); + indicator.setText(title); } try { action.run(); } finally { if (title != null) { - context.getProgressIndicator().popState(); + indicator.popState(); } } } diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/DummyCompileContext.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/DummyCompileContext.java index af4752e80675..f308bd980aa5 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/DummyCompileContext.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/DummyCompileContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -61,6 +61,7 @@ public class DummyCompileContext implements CompileContext { return 0; } + @NotNull public ProgressIndicator getProgressIndicator() { return null; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index 1b78472e256f..c61d48df4714 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -67,8 +67,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { } TextRange curLineRange = DocumentUtil.getLineTextRange(doc, line); PsiElement element = position.getElementAt(); - PsiParameterListOwner method = DebuggerUtilsEx.getContainingMethod(element); - PsiElement body = method != null ? method.getBody() : null; + PsiElement body = DebuggerUtilsEx.getBody(DebuggerUtilsEx.getContainingMethod(element)); final TextRange lineRange = (body != null) ? curLineRange.intersection(body.getTextRange()) : curLineRange; if (lineRange == null || lineRange.isEmpty()) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java b/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java index ff15205d1e9c..cc42a83cd616 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -73,7 +73,7 @@ public class BasicStepMethodFilter implements NamedMethodFilter { lambdaMatched = ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Boolean compute() { - PsiParameterListOwner psiMethod = DebuggerUtilsEx.getContainingMethod(process.getPositionManager().getSourcePosition(location)); + PsiElement psiMethod = DebuggerUtilsEx.getContainingMethod(process.getPositionManager().getSourcePosition(location)); if (psiMethod instanceof PsiLambdaExpression) { PsiType type = ((PsiLambdaExpression)psiMethod).getFunctionalInterfaceType(); PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(type); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 1bc5a1af33a5..3c0ed6780f10 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -230,14 +230,14 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio if (name != null && !name.equals(myExpectedClassName)) { return null; } - PsiParameterListOwner method = DebuggerUtilsEx.getContainingMethod(element); + PsiElement method = DebuggerUtilsEx.getContainingMethod(element); if (!StringUtil.isEmpty(myExpectedMethodName)) { if (method == null) { return null; } else if (((method instanceof PsiMethod && myExpectedMethodName.equals(((PsiMethod)method).getName())) || (method instanceof PsiLambdaExpression && LambdaMethodFilter.isLambdaName(myExpectedMethodName))) && - insideBody(element, method.getBody())) { + insideBody(element, DebuggerUtilsEx.getBody(method))) { return element; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java index 7ae4204fe882..68c949e0bb2e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -845,6 +845,25 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils { return lambdas; } + @Nullable + public static PsiElement getBody(PsiElement method) { + if (method instanceof PsiParameterListOwner) { + return ((PsiParameterListOwner)method).getBody(); + } + else if (method instanceof PsiClassInitializer) { + return ((PsiClassInitializer)method).getBody(); + } + return null; + } + + @NotNull + public static PsiParameter[] getParameters(PsiElement method) { + if (method instanceof PsiParameterListOwner) { + return ((PsiParameterListOwner)method).getParameterList().getParameters(); + } + return PsiParameter.EMPTY_ARRAY; + } + public static boolean intersects(@NotNull TextRange range, @NotNull PsiElement elem) { TextRange elemRange = elem.getTextRange(); return elemRange != null && elemRange.intersects(range); @@ -888,12 +907,12 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils { } @Nullable - public static PsiParameterListOwner getContainingMethod(@Nullable PsiElement elem) { - return PsiTreeUtil.getContextOfType(elem, PsiMethod.class, PsiLambdaExpression.class); + public static PsiElement getContainingMethod(@Nullable PsiElement elem) { + return PsiTreeUtil.getContextOfType(elem, PsiMethod.class, PsiLambdaExpression.class, PsiClassInitializer.class); } @Nullable - public static PsiParameterListOwner getContainingMethod(@Nullable SourcePosition position) { + public static PsiElement getContainingMethod(@Nullable SourcePosition position) { if (position == null) return null; return getContainingMethod(position.getElementAt()); } diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java index 50a03a53fd3d..1ee6c1a8ee04 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -323,18 +323,15 @@ public class LocalVariablesUtil { SourcePosition position = ContextUtil.getSourcePosition(context); if (position != null) { PsiElement element = position.getElementAt(); - PsiParameterListOwner method = DebuggerUtilsEx.getContainingMethod(element); + PsiElement method = DebuggerUtilsEx.getContainingMethod(element); if (method != null) { - PsiParameterList params = method.getParameterList(); MultiMap res = new MultiMap(); - int psiFirstLocalsSlot = getFirstLocalsSlot(method); - int slot = Math.max(0, firstLocalsSlot - psiFirstLocalsSlot); - for (int i = 0; i < params.getParametersCount(); i++) { - PsiParameter parameter = params.getParameters()[i]; + int slot = Math.max(0, firstLocalsSlot - getFirstLocalsSlot(method)); + for (PsiParameter parameter : DebuggerUtilsEx.getParameters(method)) { res.putValue(slot, parameter.getName()); slot += getTypeSlotSize(parameter.getType()); } - PsiElement body = method.getBody(); + PsiElement body = DebuggerUtilsEx.getBody(method); if (body != null) { try { body.accept(new LocalVariableNameFinder(firstLocalsSlot, res, element)); @@ -481,13 +478,12 @@ public class LocalVariablesUtil { } } - private static int getFirstLocalsSlot(PsiParameterListOwner method) { + private static int getFirstLocalsSlot(PsiElement method) { int startSlot = 0; if (method instanceof PsiModifierListOwner) { startSlot = ((PsiModifierListOwner)method).hasModifierProperty(PsiModifier.STATIC) ? 0 : 1; } - PsiParameterList params = method.getParameterList(); - for (PsiParameter parameter : params.getParameters()) { + for (PsiParameter parameter : DebuggerUtilsEx.getParameters(method)) { startSlot += getTypeSlotSize(parameter.getType()); } return startSlot; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java index 361101abea5f..50ac2b9474f3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -123,7 +123,7 @@ public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase res = new SmartList(); res.add(new JavaBreakpointVariant(position)); //all - if (startMethod instanceof PsiMethod) { + if (!(startMethod instanceof PsiLambdaExpression)) { res.add(new ExactJavaBreakpointVariant(position, startMethod, -1)); // base method } diff --git a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java index 4bb082b1d29c..f5ce0f3e0442 100644 --- a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java +++ b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java @@ -322,8 +322,7 @@ public abstract class JavaTestFrameworkRunnableState getPosition(Location location) { final PsiElement psiElement = location.getPsiElement(); final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(psiElement, PsiMethod.class); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/TrivialMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/TrivialMethodReferenceInspection.java new file mode 100644 index 000000000000..c2678959d23c --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/TrivialMethodReferenceInspection.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2016 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.codeInspection; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignatureUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +public class TrivialMethodReferenceInspection extends BaseJavaBatchLocalInspectionTool { + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + final PsiElement referenceNameElement = expression.getReferenceNameElement(); + if (qualifierExpression != null && referenceNameElement != null) { + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(expression); + if (interfaceMethod != null) { + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiMethod && + (interfaceMethod == resolve || MethodSignatureUtil.isSuperMethod(interfaceMethod, (PsiMethod)resolve))) { + holder.registerProblem(referenceNameElement, "Method reference can be replaced with qualifier", new ReplaceMethodRefWithQualifierFix()); + } + } + } + } + }; + } + + private static class ReplaceMethodRefWithQualifierFix implements LocalQuickFix { + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace with qualifier"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + final PsiElement parent = element != null ? element.getParent() : null; + if (parent instanceof PsiMethodReferenceExpression) { + final PsiExpression qualifierExpression = ((PsiMethodReferenceExpression)parent).getQualifierExpression(); + if (qualifierExpression != null) { + parent.replace(qualifierExpression); + } + } + } + } +} diff --git a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java index 38563a0d62da..53a3a670c1c9 100644 --- a/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java +++ b/java/java-analysis-impl/src/com/intellij/find/findUsages/JavaFindUsagesHelper.java @@ -294,31 +294,35 @@ public class JavaFindUsagesHelper { progress.pushState(); } - List classes = new ArrayList(); - addClassesInPackage(aPackage, options.isIncludeSubpackages, classes); - for (final PsiClass aClass : classes) { - if (progress != null) { - String name = ApplicationManager.getApplication().runReadAction(new Computable() { + try { + List classes = new ArrayList(); + addClassesInPackage(aPackage, options.isIncludeSubpackages, classes); + for (final PsiClass aClass : classes) { + if (progress != null) { + String name = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return aClass.getName(); + } + }); + progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", name)); + progress.checkCanceled(); + } + boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { @Override - public String compute() { - return aClass.getName(); + public boolean processInReadAction(final PsiReference psiReference) { + return addResult(psiReference, options, processor); } }); - progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", name)); - progress.checkCanceled(); + if (!success) return false; + } + } + finally { + if (progress != null){ + progress.popState(); } - boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor() { - @Override - public boolean processInReadAction(final PsiReference psiReference) { - return addResult(psiReference, options, processor); - } - }); - if (!success) return false; } - if (progress != null){ - progress.popState(); - } return true; } @@ -345,7 +349,7 @@ public class JavaFindUsagesHelper { if (includeSubdirs) { PsiDirectory[] dirs = dir.getSubdirectories(); for (PsiDirectory directory : dirs) { - addClassesInDirectory(directory, includeSubdirs, array); + addClassesInDirectory(directory, true, array); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index efc782949fdc..88efb04b4827 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -315,14 +315,10 @@ public abstract class ImportClassFixBase 1, getMethodPresentableText()); if (!ApplicationManager.getApplication().isUnitTestMode() && !HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) { - final PsiMethodCallExpression element = myMethodCall.getElement(); final TextRange textRange = element.getTextRange(); HintManager.getInstance().showQuestionHint(editor, hintText, textRange.getStartOffset(), diff --git a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java index 6665831ef3a0..eb7edaa47f78 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureDialog.java @@ -180,7 +180,7 @@ public class ChangeClassSignatureDialog extends RefactoringDialog { TableUtil.stopEditing(myTable); String message = validateAndCommitData(); if (message != null) { - CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.incorrect.data"), message, HelpID.CHANGE_SIGNATURE, myClass.getProject()); + CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.incorrect.data"), message, HelpID.CHANGE_CLASS_SIGNATURE, myClass.getProject()); return; } ChangeClassSignatureProcessor processor = diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodHandler.java index 4aeec6d791a5..a086d22b565e 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodHandler.java @@ -83,11 +83,6 @@ class InlineMethodHandler extends JavaInlineActionHandler { return; } - if (reference instanceof PsiMethodReferenceExpression) { - CommonRefactoringUtil.showErrorHint(project, editor, REFACTORING_NAME + " cannot be applied to method references", REFACTORING_NAME, HelpID.INLINE_METHOD); - return; - } - if (reference != null) { final String errorMessage = InlineMethodProcessor.checkCalledInSuperOrThisExpr(methodBody, reference.getElement()); if (errorMessage != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index b2c82e29a2bb..873ff1427fce 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -57,6 +57,7 @@ import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; +import com.siyeh.ig.psiutils.SideEffectChecker; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -193,7 +194,14 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { conflicts.putValue(element, "Inlined method is used in javadoc"); } if (element instanceof PsiMethodReferenceExpression) { - conflicts.putValue(element, "Inlined method is used in method reference"); + final PsiExpression qualifierExpression = ((PsiMethodReferenceExpression)element).getQualifierExpression(); + if (qualifierExpression != null) { + final List sideEffects = new ArrayList(); + SideEffectChecker.checkSideEffects(qualifierExpression, sideEffects); + if (!sideEffects.isEmpty()) { + conflicts.putValue(element, "Inlined method is used in method reference with side effects in qualifier"); + } + } } final String errorMessage = checkCalledInSuperOrThisExpr(myMethod.getBody(), element); @@ -412,14 +420,24 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { try { if (myInlineThisOnly) { if (myMethod.isConstructor() && InlineMethodHandler.isChainingConstructor(myMethod)) { - PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall(myReference); - if (constructorCall != null) { - inlineConstructorCall(constructorCall); + if (myReference instanceof PsiMethodReferenceExpression) { + inlineMethodReference((PsiMethodReferenceExpression)myReference); + } + else { + PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall(myReference); + if (constructorCall != null) { + inlineConstructorCall(constructorCall); + } } } else { myReference = addBracesWhenNeeded(new PsiReferenceExpression[]{(PsiReferenceExpression)myReference})[0]; - inlineMethodCall((PsiReferenceExpression)myReference); + if (myReference instanceof PsiMethodReferenceExpression) { + inlineMethodReference((PsiMethodReferenceExpression)myReference); + } + else { + inlineMethodCall((PsiReferenceExpression)myReference); + } } } else { @@ -427,7 +445,10 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { if (myMethod.isConstructor()) { for (UsageInfo usage : usages) { PsiElement element = usage.getElement(); - if (element instanceof PsiJavaCodeReferenceElement) { + if (element instanceof PsiMethodReferenceExpression) { + inlineMethodReference((PsiMethodReferenceExpression)element); + } + else if (element instanceof PsiJavaCodeReferenceElement) { PsiCall constructorCall = RefactoringUtil.getEnclosingConstructorCall((PsiJavaCodeReferenceElement)element); if (constructorCall != null) { inlineConstructorCall(constructorCall); @@ -449,7 +470,8 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { final PsiElement element = usage.getElement(); if (element instanceof PsiReferenceExpression) { refExprList.add((PsiReferenceExpression)element); - } else if (element instanceof PsiImportStaticReferenceElement) { + } + else if (element instanceof PsiImportStaticReferenceElement) { final JavaResolveResult[] resolveResults = ((PsiImportStaticReferenceElement)element).multiResolve(false); if (resolveResults.length < 2) { //no overloads available: ensure broken import are deleted and @@ -464,8 +486,12 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { PsiReferenceExpression[] refs = refExprList.toArray(new PsiReferenceExpression[refExprList.size()]); refs = addBracesWhenNeeded(refs); for (PsiReferenceExpression ref : refs) { - if (ref instanceof PsiMethodReferenceExpression) continue; - inlineMethodCall(ref); + if (ref instanceof PsiMethodReferenceExpression) { + inlineMethodReference((PsiMethodReferenceExpression)ref); + } + else { + inlineMethodCall(ref); + } } for (PsiElement psiElement : imports2Delete) { if (psiElement != null && psiElement.isValid()) { @@ -482,6 +508,25 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { } } + private void inlineMethodReference(PsiMethodReferenceExpression reference) { + final PsiLambdaExpression lambdaExpression = LambdaRefactoringUtil.convertMethodReferenceToLambda(reference, false, false); + final PsiExpression callExpression = LambdaUtil.extractSingleExpressionFromBody(lambdaExpression.getBody()); + if (callExpression instanceof PsiMethodCallExpression) { + inlineMethodCall(((PsiMethodCallExpression)callExpression).getMethodExpression()); + } + else if (callExpression instanceof PsiCall) { + inlineConstructorCall((PsiCall)callExpression); + } + else { + LOG.error("Unexpected expr: " + callExpression.getText()); + } + LambdaRefactoringUtil.simplifyToExpressionLambda(lambdaExpression); + + if (myInlineThisOnly) { + LambdaRefactoringUtil.removeSideEffectsFromLambdaBody(myEditor, lambdaExpression); + } + } + public static void inlineConstructorCall(PsiCall constructorCall) { final PsiMethod oldConstructor = constructorCall.resolveMethod(); LOG.assertTrue(oldConstructor != null); @@ -1234,12 +1279,17 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { myAddedClassInitializers = new HashMap(); for (PsiReferenceExpression ref : refs) { + if (ref instanceof PsiMethodReferenceExpression) continue; ref.putCopyableUserData(MARK_KEY, ""); } RefLoop: for (PsiReferenceExpression ref : refs) { if (!ref.isValid()) continue; + if (ref instanceof PsiMethodReferenceExpression) { + refsVector.add(ref); + continue; + } PsiElement parentStatement = RefactoringUtil.getParentStatement(ref, true); if (parentStatement != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 5becbc3622d0..a3fd53d37421 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -172,7 +172,7 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { return true; } }); - if (!overriders.isEmpty()) { + if (overriders.size() > 1) { String message = RefactoringBundle.message("0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.type.parameters", UsageViewUtil.getLongName(owner)); int result = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES :Messages.showYesNoCancelDialog(project, message, SafeDeleteHandler.REFACTORING_NAME, Messages.getQuestionIcon()); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index 09a76bd71359..8dc5dfd43f8d 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -39,12 +39,13 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.rename.RenameProcessor; +import com.intellij.refactoring.typeCook.deductive.PsiExtendedTypeVisitor; import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; -import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.usageView.UsageInfo; import com.intellij.util.*; +import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.*; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.GraphGenerator; @@ -64,7 +65,8 @@ import java.util.HashSet; public class TypeMigrationLabeler { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.typeMigration.TypeMigrationLabeler"); private boolean myShowWarning = true; - private MigrateException myException; + private volatile MigrateException myException; + private final Semaphore myDialogSemaphore = new Semaphore(); public TypeMigrationRules getRules() { return myRules; @@ -74,7 +76,7 @@ public class TypeMigrationLabeler { private final Function myMigrationRootTypeFunction; private TypeEvaluator myTypeEvaluator; private final LinkedHashMap myConversions; - private final HashSet, PsiType>> myFailedConversions; + private final Map, PsiType>, TypeMigrationUsageInfo> myFailedConversions; private LinkedList> myMigrationRoots; private final LinkedHashMap myNewExpressionTypeChange; private final LinkedHashMap myClassTypeArgumentsChange; @@ -96,7 +98,7 @@ public class TypeMigrationLabeler { myMigrationRootTypeFunction = migrationRootTypeFunction; myConversions = new LinkedHashMap(); - myFailedConversions = new HashSet, PsiType>>(); + myFailedConversions = new LinkedHashMap, PsiType>, TypeMigrationUsageInfo>(); myNewExpressionTypeChange = new LinkedHashMap(); myClassTypeArgumentsChange = new LinkedHashMap(); } @@ -113,7 +115,7 @@ public class TypeMigrationLabeler { final String[] report = new String[myFailedConversions.size()]; int j = 0; - for (final Pair, PsiType> p : myFailedConversions) { + for (final Pair, PsiType> p : myFailedConversions.keySet()) { final PsiExpression element = p.getFirst().getElement(); LOG.assertTrue(element != null); final PsiType type = element.getType(); @@ -128,24 +130,39 @@ public class TypeMigrationLabeler { return report; } + public UsageInfo[] getFailedUsages(final TypeMigrationUsageInfo root) { + return map2Usages(ContainerUtil.mapNotNull(myFailedConversions.entrySet(), + new Function, PsiType>, TypeMigrationUsageInfo>, Pair, PsiType>>() { + @Override + public Pair, PsiType> fun(Map.Entry, PsiType>, TypeMigrationUsageInfo> entry) { + return entry.getValue().equals(root) ? entry.getKey() : null; + } + })); + } + public UsageInfo[] getFailedUsages() { - final List usages = new ArrayList(myFailedConversions.size()); - for (final Pair, PsiType> p : myFailedConversions) { - final PsiExpression expr = p.getFirst().getElement(); - if (expr != null) { - usages.add(new UsageInfo(expr) { + return map2Usages(myFailedConversions.keySet()); + } + + @NotNull + private static UsageInfo[] map2Usages(Collection, PsiType>> usages) { + return ContainerUtil + .map2Array(usages, new UsageInfo[usages.size()], new Function, PsiType>, UsageInfo>() { + @Override + public UsageInfo fun(final Pair, PsiType> pair) { + final PsiExpression expr = pair.getFirst().getElement(); + LOG.assertTrue(expr != null); + return new UsageInfo(expr) { @Nullable public String getTooltipText() { final PsiType type = expr.isValid() ? expr.getType() : null; if (type == null) return null; return "Cannot convert type of the expression from " + - type.getCanonicalText() + " to " + p.getSecond().getCanonicalText(); + type.getCanonicalText() + " to " + pair.getSecond().getCanonicalText(); } - }); + }; } - } - - return usages.toArray(new UsageInfo[usages.size()]); + }); } public TypeMigrationUsageInfo[] getMigratedUsages() { @@ -523,11 +540,20 @@ public class TypeMigrationLabeler { if (!userDefinedType) { final Set collector; - final PsiType rootInitialType = getElementType(getCurrentRoot().getElement()); - if (rootInitialType instanceof PsiClassReferenceType) { - collector = new HashSet(); - final PsiJavaCodeReferenceElement reference = ((PsiClassReferenceType)rootInitialType).getReference(); - RefactoringUtil.collectTypeParameters(collector, reference); + if (type instanceof PsiClassReferenceType) { + collector = type.accept(new PsiExtendedTypeVisitor>() { + private final Set myResult = new HashSet(); + + @Override + public Set visitClassType(PsiClassType classType) { + super.visitClassType(classType); + final PsiClass resolved = classType.resolve(); + if (resolved instanceof PsiTypeParameter) { + myResult.add((PsiTypeParameter) resolved); + } + return myResult; + } + }); } else { collector = Collections.emptySet(); } @@ -732,6 +758,7 @@ public class TypeMigrationLabeler { boolean addRoot(final TypeMigrationUsageInfo usageInfo, final PsiType type, final PsiElement place, boolean alreadyProcessed) { if (myShowWarning && myMigrationRoots.size() > 10 && !ApplicationManager.getApplication().isUnitTestMode()) { myShowWarning = false; + myDialogSemaphore.down(); try { final Runnable checkTimeToStopRunnable = new Runnable() { public void run() { @@ -739,6 +766,7 @@ public class TypeMigrationLabeler { Messages.getWarningIcon()) == Messages.YES) { myException = new MigrateException(); } + myDialogSemaphore.up(); } }; SwingUtilities.invokeLater(checkTimeToStopRunnable); @@ -747,7 +775,7 @@ public class TypeMigrationLabeler { //do nothing } } - if (myException != null) throw myException; + checkInterrupted(); rememberRootTrace(usageInfo, type, place, alreadyProcessed); if (!alreadyProcessed && !(usageInfo.getElement() instanceof PsiExpression) && !getTypeEvaluator().setType(usageInfo, type)) { alreadyProcessed = true; @@ -757,6 +785,10 @@ public class TypeMigrationLabeler { return alreadyProcessed; } + private void checkInterrupted() { + if (myException != null) throw myException; + } + private void rememberRootTrace(final TypeMigrationUsageInfo usageInfo, final PsiType type, final PsiElement place, final boolean alreadyProcessed) { if (myCurrentRoot != null) { if (!alreadyProcessed) { @@ -795,7 +827,11 @@ public class TypeMigrationLabeler { void markFailedConversion(final Pair typePair, final PsiExpression expression) { LOG.assertTrue(typePair.getSecond() != null); - myFailedConversions.add(Pair.create(SmartPointerManager.getInstance(expression.getProject()).createSmartPsiElementPointer(expression), typePair.getSecond())); + final Pair, PsiType> key = + Pair.create(SmartPointerManager.getInstance(expression.getProject()).createSmartPsiElementPointer(expression), typePair.getSecond()); + if (!myFailedConversions.containsKey(key)) { + myFailedConversions.put(key, getCurrentRoot()); + } } void setConversionMapping(final PsiExpression expression, final Object obj) { @@ -995,6 +1031,9 @@ public class TypeMigrationLabeler { iterate(); } } + + myDialogSemaphore.waitFor(); + checkInterrupted(); } public TypeEvaluator getTypeEvaluator() { @@ -1092,7 +1131,7 @@ public class TypeMigrationLabeler { buffer.append("Fails:\n"); final ArrayList, PsiType>> - failsList = new ArrayList, PsiType>>(myFailedConversions); + failsList = new ArrayList, PsiType>>(myFailedConversions.keySet()); Collections.sort(failsList, new Comparator, PsiType>>() { public int compare(final Pair, PsiType> o1, final Pair, PsiType> o2) { final PsiElement element1 = o1.getFirst().getElement(); diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index a5c757d14b05..bfbb4cfe2b76 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -449,8 +449,8 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { final PsiType qualifierType = qualifier.getType(); if (qualifierType instanceof PsiClassType) { final PsiClassType.ClassResolveResult classResolveResult = ((PsiClassType)qualifierType).resolveGenerics(); - final PsiType migrationType = - classResolveResult.getSubstitutor().substitute(evalSubstitutor.substitute(JavaPsiFacade.getElementFactory(myStatement.getProject()).createType(classResolveResult.getElement(), PsiSubstitutor.EMPTY))); + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myStatement.getProject()); + final PsiType migrationType = elementFactory.createType(classResolveResult.getElement(), composeIfNotAssignable(classResolveResult.getSubstitutor(), evalSubstitutor)); myLabeler.migrateExpressionType(qualifier, migrationType, myStatement, migrationType.equals(qualifierType), true); } } @@ -650,4 +650,23 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { } return false; } + + private static PsiSubstitutor composeIfNotAssignable(PsiSubstitutor actual, PsiSubstitutor required) { + if (actual == PsiSubstitutor.EMPTY) { + return required; + } + if (required == PsiSubstitutor.EMPTY) { + return actual; + } + PsiSubstitutor result = PsiSubstitutorImpl.createSubstitutor(actual.getSubstitutionMap()); + for (Map.Entry e : required.getSubstitutionMap().entrySet()) { + final PsiTypeParameter typeParameter = e.getKey(); + final PsiType requiredType = e.getValue(); + final PsiType actualType = result.getSubstitutionMap().get(typeParameter); + if (requiredType != null && (actualType == null || !TypeConversionUtil.isAssignable(actualType, requiredType))) { + result = result.put(typeParameter, requiredType); + } + } + return result; + } } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java index 63a3b41bbb9a..a9c6f81f4e17 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/MigrationPanel.java @@ -161,7 +161,7 @@ public class MigrationPanel extends JPanel implements Disposable { final Object userObject = migrationNodes[0].getUserObject(); if (userObject instanceof MigrationNode) { final MigrationNode migrationNode = (MigrationNode)userObject; - final UsageInfo[] failedUsages = myLabeler.getFailedUsages(); + final UsageInfo[] failedUsages = myLabeler.getFailedUsages(migrationNode.getInfo()); if (failedUsages.length > 0) { myConflictsPanel.showUsages(PsiElement.EMPTY_ARRAY, failedUsages); } diff --git a/java/java-impl/src/com/intellij/refactoring/util/LambdaRefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/LambdaRefactoringUtil.java new file mode 100644 index 000000000000..b3b218b41634 --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/util/LambdaRefactoringUtil.java @@ -0,0 +1,263 @@ +/* + * Copyright 2000-2016 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.refactoring.util; + +import com.intellij.codeInspection.RedundantLambdaCodeBlockInspection; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.RedundantCastUtil; +import com.intellij.refactoring.introduceField.ElementToWorkOn; +import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler; +import com.intellij.util.Function; +import com.intellij.util.text.UniqueNameGenerator; +import com.siyeh.ig.psiutils.SideEffectChecker; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LambdaRefactoringUtil { + private static final Logger LOG = Logger.getInstance("#" + LambdaRefactoringUtil.class.getName()); + + @NotNull + public static PsiLambdaExpression convertMethodReferenceToLambda(final PsiMethodReferenceExpression referenceExpression, + final boolean ignoreCast, + final boolean simplifyToExpressionLambda) { + final PsiElement resolve = referenceExpression.resolve(); + final PsiType functionalInterfaceType = referenceExpression.getFunctionalInterfaceType(); + final PsiClassType.ClassResolveResult functionalInterfaceResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); + LOG.assertTrue(interfaceMethod != null); + final PsiSubstitutor psiSubstitutor = LambdaUtil.getSubstitutor(interfaceMethod, functionalInterfaceResolveResult); + final MethodSignature signature = interfaceMethod.getSignature(psiSubstitutor); + final boolean isReceiver; + if (resolve instanceof PsiMethod){ + final PsiMethod method = (PsiMethod)resolve; + isReceiver = PsiMethodReferenceUtil.isResolvedBySecondSearch(referenceExpression, signature, + method.isVarArgs(), + method.hasModifierProperty(PsiModifier.STATIC), + method.getParameterList().getParametersCount()); + } + else { + isReceiver = false; + } + final PsiParameter[] psiParameters = resolve instanceof PsiMethod ? ((PsiMethod)resolve).getParameterList().getParameters() : null; + + final StringBuilder buf = new StringBuilder("("); + LOG.assertTrue(functionalInterfaceType != null); + buf.append(GenericsUtil.getVariableTypeByExpressionType(functionalInterfaceType).getCanonicalText()).append(")("); + final PsiParameterList parameterList = interfaceMethod.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + + final Map map = new HashMap(); + final UniqueNameGenerator nameGenerator = new UniqueNameGenerator(); + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(referenceExpression.getProject()); + final String paramsString = StringUtil.join(parameters, new Function() { + @Override + public String fun(PsiParameter parameter) { + final int parameterIndex = parameterList.getParameterIndex(parameter); + String baseName; + if (isReceiver && parameterIndex == 0) { + final SuggestedNameInfo + nameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, psiSubstitutor.substitute(parameter.getType())); + baseName = nameInfo.names.length > 0 ? nameInfo.names[0] : parameter.getName(); + } + else { + final String initialName; + if (psiParameters != null) { + final int idx = parameterIndex - (isReceiver ? 1 : 0); + initialName = psiParameters.length > 0 ? psiParameters[idx < psiParameters.length ? idx : psiParameters.length - 1].getName() + : parameter.getName(); + } + else { + initialName = parameter.getName(); + } + baseName = codeStyleManager.variableNameToPropertyName(initialName, VariableKind.PARAMETER); + } + + if (baseName != null) { + String parameterName = nameGenerator.generateUniqueName(codeStyleManager.suggestUniqueVariableName(baseName, referenceExpression, true)); + map.put(parameter, parameterName); + return parameterName; + } + return ""; + } + }, ", "); + buf.append(paramsString); + buf.append(") -> "); + + + final JavaResolveResult resolveResult = referenceExpression.advancedResolve(false); + final PsiElement resolveElement = resolveResult.getElement(); + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(referenceExpression.getProject()); + if (resolveElement instanceof PsiMember) { + + buf.append("{"); + + if (!PsiType.VOID.equals(interfaceMethod.getReturnType())) { + buf.append("return "); + } + final PsiElement qualifier = referenceExpression.getQualifier(); + PsiClass containingClass = null; + if (resolveElement instanceof PsiMethod) { + containingClass = ((PsiMember)resolveElement).getContainingClass(); + LOG.assertTrue(containingClass != null); + } else if (resolveElement instanceof PsiClass) { + containingClass = (PsiClass)resolveElement; + } + + final boolean onArrayRef = + elementFactory.getArrayClass(PsiUtil.getLanguageLevel(referenceExpression)) == containingClass; + + final PsiElement referenceNameElement = referenceExpression.getReferenceNameElement(); + if (isReceiver){ + buf.append(map.get(parameters[0])).append("."); + } else { + if (!(referenceNameElement instanceof PsiKeyword)) { + if (qualifier instanceof PsiTypeElement) { + final PsiJavaCodeReferenceElement referenceElement = ((PsiTypeElement)qualifier).getInnermostComponentReferenceElement(); + LOG.assertTrue(referenceElement != null); + buf.append(referenceElement.getReferenceName()).append("."); + } + else if (qualifier != null && !(qualifier instanceof PsiThisExpression && ((PsiThisExpression)qualifier).getQualifier() == null)) { + buf.append(qualifier.getText()).append("."); + } + } + } + + //new or method name + buf.append(referenceExpression.getReferenceName()); + + if (referenceNameElement instanceof PsiKeyword) { + //class name + buf.append(" "); + if (onArrayRef) { + if (qualifier instanceof PsiTypeElement) { + final PsiType type = ((PsiTypeElement)qualifier).getType(); + int dim = type.getArrayDimensions(); + buf.append(type.getDeepComponentType().getCanonicalText()); + buf.append("["); + buf.append(map.get(parameters[0])); + buf.append("]"); + while (--dim > 0) { + buf.append("[]"); + } + } + } else { + buf.append(((PsiMember)resolveElement).getName()); + + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + + LOG.assertTrue(containingClass != null); + if (containingClass.hasTypeParameters() && !PsiUtil.isRawSubstitutor(containingClass, substitutor)) { + buf.append("<").append(StringUtil.join(containingClass.getTypeParameters(), new Function() { + @Override + public String fun(PsiTypeParameter parameter) { + final PsiType psiType = substitutor.substitute(parameter); + LOG.assertTrue(psiType != null); + return psiType.getCanonicalText(); + } + }, ", ")).append(">"); + } + } + } + + if (!onArrayRef || isReceiver) { + //param list + buf.append("("); + boolean first = true; + for (int i = isReceiver ? 1 : 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + if (!first) { + buf.append(", "); + } else { + first = false; + } + buf.append(map.get(parameter)); + } + buf.append(")"); + } + + buf.append(";}"); + } + + + final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)referenceExpression.replace(elementFactory.createExpressionFromText(buf.toString(), referenceExpression)); + PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)typeCastExpression.getOperand(); + LOG.assertTrue(lambdaExpression != null, buf.toString()); + if (RedundantCastUtil.isCastRedundant(typeCastExpression) || ignoreCast) { + final PsiExpression operand = typeCastExpression.getOperand(); + LOG.assertTrue(operand != null); + lambdaExpression = (PsiLambdaExpression)typeCastExpression.replace(operand); + } + + if (simplifyToExpressionLambda) { + simplifyToExpressionLambda(lambdaExpression); + } + + return lambdaExpression; + } + + public static void simplifyToExpressionLambda(@NotNull final PsiLambdaExpression lambdaExpression) { + final PsiElement body = lambdaExpression.getBody(); + final PsiExpression singleExpression = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(lambdaExpression, body); + if (singleExpression != null) { + body.replace(singleExpression); + } + } + + /** + * Works for expression lambdas/one statement code block lambdas to ensures equivalent method ref -> lambda transformation. + */ + public static void removeSideEffectsFromLambdaBody(Editor editor, PsiLambdaExpression lambdaExpression) { + if (lambdaExpression != null && lambdaExpression.isValid()) { + final PsiElement body = lambdaExpression.getBody(); + PsiExpression methodCall = LambdaUtil.extractSingleExpressionFromBody(body); + PsiExpression qualifierExpression = null; + if (methodCall instanceof PsiMethodCallExpression) { + qualifierExpression = ((PsiMethodCallExpression)methodCall).getMethodExpression().getQualifierExpression(); + } + else if (methodCall instanceof PsiNewExpression) { + qualifierExpression = ((PsiNewExpression)methodCall).getQualifier(); + } + + if (qualifierExpression != null) { + final List sideEffects = new ArrayList(); + SideEffectChecker.checkSideEffects(qualifierExpression, sideEffects); + if (!sideEffects.isEmpty()) { + if (ApplicationManager.getApplication().isUnitTestMode() || + Messages.showYesNoDialog(lambdaExpression.getProject(), "There are possible side effects found in method reference qualifier." + + "\nIntroduce local variable?", "Side Effects Detected", Messages.getQuestionIcon()) == Messages.YES) { + //ensure introduced before lambda + qualifierExpression.putUserData(ElementToWorkOn.PARENT, lambdaExpression); + new IntroduceVariableHandler().invoke(qualifierExpression.getProject(), editor, qualifierExpression); + } + } + } + } + } +} diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java index b6f1d08b2111..af9e4481d1bf 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java @@ -64,11 +64,15 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase consumer, diff --git a/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementVisitor.java b/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementVisitor.java index 9cc26549c24f..1a18e7b48d53 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementVisitor.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -21,6 +21,13 @@ package com.intellij.psi; import com.intellij.util.containers.Stack; +/** + * a JavaElementVisitor which also visits all children elements + * in a tree pre-order, see Tree traversal:Pre-order for details. + *

+ * Note: This visitor handles all elements recursively, so it can consume a large amount of stack space for very deep trees. + * For such deep trees please consider using {@link JavaRecursiveElementWalkingVisitor} instead. + */ public abstract class JavaRecursiveElementVisitor extends JavaElementVisitor { // This stack thing is intended to prevent exponential child traversing due to visitReferenceExpression calls both visitRefElement // and visitExpression. diff --git a/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementWalkingVisitor.java b/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementWalkingVisitor.java index d5ed67d3525c..9cbb53998336 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementWalkingVisitor.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaRecursiveElementWalkingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -21,6 +21,13 @@ package com.intellij.psi; import org.jetbrains.annotations.NotNull; +/** + * a JavaElementVisitor which also visits all children elements + * in a tree pre-order, see Tree traversal:Pre-order for details. + *

+ * Note: This visitor handles all containing elements without consuming stack space, so it can be used even for very deep trees. + * Note 2: This visitor works for source-based PSI only. Any elements implementing {@link PsiCompiledElement} will be rejected. + */ public abstract class JavaRecursiveElementWalkingVisitor extends JavaElementVisitor { private final PsiWalkingState myWalkingState = new PsiWalkingState(this){ @Override diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 7e0786281066..5872b4f76d96 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -520,7 +520,8 @@ public class LambdaUtil { } else if (statements[0] instanceof PsiExpressionStatement) { expression = ((PsiExpressionStatement)statements[0]).getExpression(); - } else if (statements[0] instanceof PsiBlockStatement) { + } + else if (statements[0] instanceof PsiBlockStatement) { return extractSingleExpressionFromBody(((PsiBlockStatement)statements[0]).getCodeBlock()); } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 6141e725b213..5da8840fc108 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -557,6 +557,9 @@ public final class PsiUtil extends PsiUtilCore { !JavaVersionService.getInstance().isAtLeast(((PsiCapturedWildcardType)lastParmType).getContext(), JavaSdkVersion.JDK_1_8)) { lastParmType = ((PsiCapturedWildcardType)lastParmType).getWildcard(); } + if (lastParmType instanceof PsiClassType) { + lastParmType = ((PsiClassType)lastParmType).setLanguageLevel(languageLevel); + } for (int i = parms.length - 1; i < args.length; i++) { PsiType argType = args[i]; if (argType == null || !function.isApplicable(lastParmType, argType, allowUncheckedConversion, i)) { diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index 9d482cd4d9a6..809dc516d992 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -78,6 +78,7 @@ public class TypeConversionUtil { return "FAKE TYPE"; } }; + private static final Key ORIGINAL_CONTEXT = Key.create("ORIGINAL_CONTEXT"); static { TYPE_TO_RANK_MAP.put(PsiType.BYTE, BYTE_RANK); @@ -1291,7 +1292,7 @@ public class TypeConversionUtil { @Override public PsiType visitClassType(PsiClassType classType) { final PsiClass aClass = classType.resolve(); - if (aClass instanceof PsiTypeParameter) { + if (aClass instanceof PsiTypeParameter && !isFreshVariable((PsiTypeParameter)aClass)) { return typeParameterErasure((PsiTypeParameter)aClass, beforeSubstitutor); } return classType.rawType(); @@ -1474,6 +1475,19 @@ public class TypeConversionUtil { return true; } + public static boolean areSameFreshVariables(PsiTypeParameter p1, PsiTypeParameter p2) { + final PsiElement originalContext = p1.getUserData(ORIGINAL_CONTEXT); + return originalContext != null && originalContext == p2.getUserData(ORIGINAL_CONTEXT); + } + + public static boolean isFreshVariable(PsiTypeParameter typeParameter) { + return typeParameter.getUserData(ORIGINAL_CONTEXT) != null; + } + + public static void markAsFreshVariable(PsiTypeParameter parameter, PsiElement context) { + parameter.putUserData(ORIGINAL_CONTEXT, context); + } + private interface Caster { @NotNull Object cast(@NotNull Object operand); diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java index 9c4492eb9cb3..e5a2ee13331b 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java @@ -16,10 +16,7 @@ package com.intellij.codeInsight; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.RecursionGuard; -import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; import com.intellij.psi.impl.PsiClassImplUtil; @@ -49,7 +46,6 @@ import java.util.*; */ public class ExceptionUtil { @NonNls private static final String CLONE_METHOD_NAME = "clone"; - public static final RecursionGuard ourThrowsGuard = RecursionManager.createGuard("checkedExceptionsGuard"); private ExceptionUtil() {} @@ -457,7 +453,7 @@ public class ExceptionUtil { return Collections.emptyList(); } - final PsiSubstitutor substitutor = getSubstitutor(result, methodCall); + final PsiSubstitutor substitutor = result.getSubstitutor(); if (!isArrayClone(method, methodCall) && methodCall instanceof PsiMethodCallExpression) { final PsiFile containingFile = (containingMethod == null ? methodCall : containingMethod).getContainingFile(); final MethodResolverProcessor processor = new MethodResolverProcessor((PsiMethodCallExpression)methodCall, containingFile); @@ -471,7 +467,7 @@ public class ExceptionUtil { if (element instanceof PsiMethod && MethodSignatureUtil.areSignaturesEqual(method, (PsiMethod)element) && !MethodSignatureUtil.isSuperMethod((PsiMethod)element, method)) { - return Pair.create((PsiMethod)element, getSubstitutor(info, methodCall)); + return Pair.create((PsiMethod)element, info.getSubstitutor()); } return null; } @@ -497,25 +493,6 @@ public class ExceptionUtil { return getUnhandledExceptions(method, methodCall, topElement, substitutor); } - private static PsiSubstitutor getSubstitutor(final JavaResolveResult result, PsiCallExpression methodCall) { - final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(methodCall, PsiLambdaExpression.class); - final PsiSubstitutor substitutor; - if (expression != null) { - final PsiElement parent = methodCall.getParent(); - final boolean callInReturnStatement = parent == expression || - parent instanceof PsiReturnStatement && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, true, PsiMethod.class) == expression; - substitutor = callInReturnStatement ? ourThrowsGuard.doPreventingRecursion(expression, false, new Computable() { - @Override - public PsiSubstitutor compute() { - return result.getSubstitutor(); - } - }) : result.getSubstitutor(); - } else { - substitutor = result.getSubstitutor(); - } - return substitutor == null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : substitutor; - } - public static void retainExceptions(List ex, List thrownEx) { final List replacement = new ArrayList(); for (Iterator iterator = ex.iterator(); iterator.hasNext(); ) { diff --git a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java index 0cf2ee42cbf3..815f47650540 100644 --- a/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java +++ b/java/java-psi-impl/src/com/intellij/psi/ClassFileViewProvider.java @@ -29,10 +29,7 @@ import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.psi.impl.file.PsiBinaryFileImpl; import org.jetbrains.annotations.NotNull; -import org.jetbrains.org.objectweb.asm.ClassReader; -import org.jetbrains.org.objectweb.asm.ClassVisitor; -import org.jetbrains.org.objectweb.asm.Label; -import org.jetbrains.org.objectweb.asm.Opcodes; +import org.jetbrains.org.objectweb.asm.*; /** * @author max @@ -79,7 +76,7 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { final Ref ref = Ref.create(Boolean.FALSE); try { - new MyClassReader(file.contentsToByteArray(false)).accept(new ClassVisitor(Opcodes.ASM5) { + new ClassReader(file.contentsToByteArray(false)).accept(new ClassVisitor(Opcodes.ASM5) { @Override public void visitOuterClass(String owner, String name, String desc) { ref.set(Boolean.TRUE); @@ -94,6 +91,11 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { throw new ProcessCanceledException(); } } + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { + throw new ProcessCanceledException(); + } }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); } catch (ProcessCanceledException ignored) { } @@ -111,15 +113,4 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider { public SingleRootFileViewProvider createCopy(@NotNull VirtualFile copy) { return new ClassFileViewProvider(getManager(), copy, false); } - - private static class MyClassReader extends ClassReader { - public MyClassReader(byte[] b) { - super(b); - } - - @Override - protected Label readLabel(int offset, Label[] labels) { - return null; - } - } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java index 4b16c7183de8..6d0d853a5098 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java @@ -26,7 +26,6 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.scope.PsiConflictResolver; @@ -535,7 +534,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); final PsiClass psiClass = resolveResult.getElement(); if (psiClass != null) { - if (psiClass instanceof PsiTypeParameter && InferenceSession.isFreshVariable((PsiTypeParameter)psiClass)) { + if (psiClass instanceof PsiTypeParameter && TypeConversionUtil.isFreshVariable((PsiTypeParameter)psiClass)) { return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 6f92e020a8cf..08fef26ae05d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -1082,7 +1082,7 @@ public class PsiClassImplUtil { PsiTypeParameter p2 = (PsiTypeParameter)another; return p1.getIndex() == p2.getIndex() && - (aClass.getManager().areElementsEquivalent(p1.getOwner(), p2.getOwner()) || InferenceSession.areSameFreshVariables(p1, p2)); + (aClass.getManager().areElementsEquivalent(p1.getOwner(), p2.getOwner()) || TypeConversionUtil.areSameFreshVariables(p1, p2)); } else { return false; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 7f963e18cbc0..a563e8107b56 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -559,7 +559,8 @@ public class ClsFileImpl extends ClsRepositoryPsiElement return myIsPhysical; } - @SuppressWarnings("UnusedDeclaration") // used by Kotlin compiler + /** @deprecated override {@link #isPhysical()} instead (to be removed in IDEA 17) */ + @SuppressWarnings("UnusedDeclaration") public void setPhysical(boolean isPhysical) { myIsPhysical = isPhysical; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index e1560cff12d7..464d8ed1e393 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -26,6 +26,7 @@ import com.intellij.psi.impl.java.stubs.impl.*; import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.stubs.StubElement; import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; import com.intellij.util.cls.ClsFormatException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +39,8 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; -import static com.intellij.psi.CommonClassNames.*; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; /** * @author max @@ -64,6 +66,7 @@ public class StubBuildingVisitor extends ClassVisitor { private final StubElement myParent; private final int myAccess; private final String myShortName; + private String myInternalName; private PsiClassStub myResult; private PsiModifierListStub myModList; @@ -82,7 +85,11 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - String fqn = getFqn(name, myShortName, myParent instanceof PsiClassStub ? ((PsiClassStub)myParent).getQualifiedName() : null); + myInternalName = name; + String parentName = myParent instanceof PsiClassStub ? ((PsiClassStub)myParent).getQualifiedName() : + myParent instanceof PsiJavaFileStub ? ((PsiJavaFileStub)myParent).getPackageName() : + null; + String fqn = getFqn(name, myShortName, parentName); String shortName = myShortName != null && name.endsWith(myShortName) ? myShortName : PsiNameHelper.getShortClassName(fqn); int flags = myAccess | access; @@ -133,37 +140,33 @@ public class StubBuildingVisitor extends ClassVisitor { convertedInterfaces.remove(JAVA_LANG_ANNOTATION_ANNOTATION); } newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, ArrayUtil.toStringArray(convertedInterfaces)); - newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult); + newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.EMPTY_STRING_ARRAY); } else { - if (convertedSuper == null || - JAVA_LANG_OBJECT.equals(convertedSuper) || - isEnum && (JAVA_LANG_ENUM.equals(convertedSuper) || (JAVA_LANG_ENUM + "<" + fqn + ">").equals(convertedSuper))) { - newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult); + if (convertedSuper == null || "java/lang/Object".equals(superName) || isEnum && "java/lang/Enum".equals(superName)) { + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, ArrayUtil.EMPTY_STRING_ARRAY); } else { - newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, convertedSuper); + newReferenceList(JavaStubElementTypes.EXTENDS_LIST, myResult, new String[]{convertedSuper}); } newReferenceList(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.toStringArray(convertedInterfaces)); } } - public static String getFqn(@NotNull String internalName, @Nullable String shortName, @Nullable String parentName) { + private static String getFqn(@NotNull String internalName, @Nullable String shortName, @Nullable String parentName) { if (shortName == null || !internalName.endsWith(shortName)) { return getClassName(internalName); } - else if (internalName.length() == shortName.length()) { + if (internalName.length() == shortName.length()) { return shortName; } - else { - if (parentName == null) { - parentName = getClassName(internalName.substring(0, internalName.length() - shortName.length() - 1)); - } - return parentName + "." + shortName; + if (parentName == null) { + parentName = getClassName(internalName.substring(0, internalName.length() - shortName.length() - 1)); } + return parentName + '.' + shortName; } - public static void newReferenceList(JavaClassReferenceListElementType type, StubElement parent, String... types) { + public static void newReferenceList(JavaClassReferenceListElementType type, StubElement parent, String[] types) { PsiReferenceList.Role role; if (type == JavaStubElementTypes.EXTENDS_LIST) role = PsiReferenceList.Role.EXTENDS_LIST; @@ -176,8 +179,8 @@ public class StubBuildingVisitor extends ClassVisitor { } @Nullable - private static String parseClassDescription(final String superName, final String[] interfaces, final List convertedInterfaces) { - final String convertedSuper = superName != null ? getClassName(superName) : null; + private static String parseClassDescription(String superName, String[] interfaces, List convertedInterfaces) { + String convertedSuper = superName != null ? getClassName(superName) : null; for (String anInterface : interfaces) { convertedInterfaces.add(getClassName(anInterface)); } @@ -185,161 +188,101 @@ public class StubBuildingVisitor extends ClassVisitor { } @Nullable - private static String parseClassSignature(final CharacterIterator signatureIterator, final List convertedInterfaces) - throws ClsFormatException { - final String convertedSuper = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); + private static String parseClassSignature(CharacterIterator signatureIterator, List convertedInterfaces) throws ClsFormatException { + String convertedSuper = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); while (signatureIterator.current() != CharacterIterator.DONE) { - final String ifs = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); + String ifs = SignatureParsing.parseTopLevelClassRefSignature(signatureIterator); if (ifs == null) throw new ClsFormatException(); - convertedInterfaces.add(ifs); } return convertedSuper; } - private static int packCommonFlags(final int access) { + private static int packCommonFlags(int access) { int flags = 0; - if ((access & Opcodes.ACC_PRIVATE) != 0) { - flags |= ModifierFlags.PRIVATE_MASK; - } - else if ((access & Opcodes.ACC_PROTECTED) != 0) { - flags |= ModifierFlags.PROTECTED_MASK; - } - else if ((access & Opcodes.ACC_PUBLIC) != 0) { - flags |= ModifierFlags.PUBLIC_MASK; - } - else { - flags |= ModifierFlags.PACKAGE_LOCAL_MASK; - } + if ((access & Opcodes.ACC_PRIVATE) != 0) flags |= ModifierFlags.PRIVATE_MASK; + else if ((access & Opcodes.ACC_PROTECTED) != 0) flags |= ModifierFlags.PROTECTED_MASK; + else if ((access & Opcodes.ACC_PUBLIC) != 0) flags |= ModifierFlags.PUBLIC_MASK; + else flags |= ModifierFlags.PACKAGE_LOCAL_MASK; - if ((access & Opcodes.ACC_STATIC) != 0) { - flags |= ModifierFlags.STATIC_MASK; - } - if ((access & Opcodes.ACC_FINAL) != 0) { - flags |= ModifierFlags.FINAL_MASK; - } + if ((access & Opcodes.ACC_STATIC) != 0) flags |= ModifierFlags.STATIC_MASK; + if ((access & Opcodes.ACC_FINAL) != 0) flags |= ModifierFlags.FINAL_MASK; return flags; } - private static int packClassFlags(final int access) { + private static int packClassFlags(int access) { int flags = packCommonFlags(access); - - if ((access & Opcodes.ACC_ABSTRACT) != 0) { - flags |= ModifierFlags.ABSTRACT_MASK; - } - + if ((access & Opcodes.ACC_ABSTRACT) != 0) flags |= ModifierFlags.ABSTRACT_MASK; return flags; } - private static int packFieldFlags(final int access) { + private static int packFieldFlags(int access) { int flags = packCommonFlags(access); - - if ((access & Opcodes.ACC_VOLATILE) != 0) { - flags |= ModifierFlags.VOLATILE_MASK; - } - if ((access & Opcodes.ACC_TRANSIENT) != 0) { - flags |= ModifierFlags.TRANSIENT_MASK; - } - + if ((access & Opcodes.ACC_VOLATILE) != 0) flags |= ModifierFlags.VOLATILE_MASK; + if ((access & Opcodes.ACC_TRANSIENT) != 0) flags |= ModifierFlags.TRANSIENT_MASK; return flags; } - private static int packMethodFlags(final int access, boolean isInterface) { + private static int packMethodFlags(int access, boolean isInterface) { int flags = packCommonFlags(access); - if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { - flags |= ModifierFlags.SYNCHRONIZED_MASK; - } - if ((access & Opcodes.ACC_NATIVE) != 0) { - flags |= ModifierFlags.NATIVE_MASK; - } - if ((access & Opcodes.ACC_ABSTRACT) != 0) { - flags |= ModifierFlags.ABSTRACT_MASK; - } - else if (isInterface && (access & Opcodes.ACC_STATIC) == 0) { - flags |= ModifierFlags.DEFENDER_MASK; - } - if ((access & Opcodes.ACC_STRICT) != 0) { - flags |= ModifierFlags.STRICTFP_MASK; - } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) flags |= ModifierFlags.SYNCHRONIZED_MASK; + if ((access & Opcodes.ACC_NATIVE) != 0) flags |= ModifierFlags.NATIVE_MASK; + if ((access & Opcodes.ACC_STRICT) != 0) flags |= ModifierFlags.STRICTFP_MASK; + + if ((access & Opcodes.ACC_ABSTRACT) != 0) flags |= ModifierFlags.ABSTRACT_MASK; + else if (isInterface && (access & Opcodes.ACC_STATIC) == 0) flags |= ModifierFlags.DEFENDER_MASK; return flags; } @Override - public void visitSource(final String source, final String debug) { + public void visitSource(String source, String debug) { ((PsiClassStubImpl)myResult).setSourceFileName(source); } @Override - public void visitOuterClass(final String owner, final String name, final String desc) { + public void visitOuterClass(String owner, String name, String desc) { if (myParent instanceof PsiFileStub) { throw new OutOfOrderInnerClassException(); } } @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - return new AnnotationTextCollector(desc, new AnnotationResultCallback() { + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new AnnotationTextCollector(desc, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); } }); } @Override - public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) { + public void visitInnerClass(String name, String outerName, String innerName, int access) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) return; - if (!isCorrectName(innerName) || outerName == null) return; + if (innerName == null || outerName == null) return; - if ((getClassName(outerName) + "." + innerName).equals(myResult.getQualifiedName())) { + if ((getClassName(outerName) + '.' + innerName).equals(myResult.getQualifiedName()) && myParent instanceof PsiFileStub) { // our result is inner class - if (myParent instanceof PsiFileStub) { - throw new OutOfOrderInnerClassException(); + throw new OutOfOrderInnerClassException(); + } + + if (myInternalName.equals(outerName)) { + T innerClass = myInnersStrategy.findInnerClass(innerName, mySource); + if (innerClass != null) { + myInnersStrategy.accept(innerClass, new StubBuildingVisitor(innerClass, myInnersStrategy, myResult, access, innerName)); } } - if (!namesEqual(outerName, myResult.getQualifiedName())) { - return; - } - - T innerClass = myInnersStrategy.findInnerClass(innerName, mySource); - if (innerClass != null) { - StubBuildingVisitor visitor = new StubBuildingVisitor(innerClass, myInnersStrategy, myResult, access, innerName); - myInnersStrategy.accept(innerClass, visitor); - } - } - - private static boolean isCorrectName(String name) { - return name != null; - } - - private static boolean namesEqual(String signature, String fqn) { - if (fqn == null) return true; // impossible case, just ignore - if (fqn.length() != signature.length()) return false; - - int p = 0; - int dot; - while ((dot = fqn.indexOf('.', p)) >= 0) { - if (!signature.regionMatches(p, fqn, p, dot - p)) { - return false; - } - char ch = signature.charAt(dot); - if (ch != '/' && ch != '$') { - return false; - } - p = dot + 1; - } - return fqn.regionMatches(p, signature, p, fqn.length() - p); } @Override @Nullable public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) return null; - if (!isCorrectName(name)) return null; + if (name == null) return null; byte flags = PsiFieldStubImpl.packFlags((access & Opcodes.ACC_ENUM) != 0, (access & Opcodes.ACC_DEPRECATED) != 0, false, false); TypeInfo type = fieldType(desc, signature); @@ -367,22 +310,18 @@ public class StubBuildingVisitor extends ClassVisitor { @NotNull private static TypeInfo fieldTypeViaDescription(@NotNull String desc) { Type type = Type.getType(desc); - final int dim = type.getSort() == Type.ARRAY ? type.getDimensions() : 0; + int dim = type.getSort() == Type.ARRAY ? type.getDimensions() : 0; if (dim > 0) { type = type.getElementType(); } - return new TypeInfo(getTypeText(type), (byte)dim, false, PsiAnnotationStub.EMPTY_ARRAY); //todo read annos from .class file + return new TypeInfo(getTypeText(type), (byte)dim, false, PsiAnnotationStub.EMPTY_ARRAY); } private static final String[] parameterNames = {"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9"}; @Override @Nullable - public MethodVisitor visitMethod(final int access, - final String name, - final String desc, - final String signature, - final String[] exceptions) { + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { // JLS 13.1 says: Any constructs introduced by the compiler that do not have a corresponding construct in the source code // must be marked as synthetic, except for default constructors and the class initialization method. // However Scala compiler erroneously generates ACC_BRIDGE instead of ACC_SYNTHETIC flag for in-trait implementation delegation. @@ -403,9 +342,9 @@ public class StubBuildingVisitor extends ClassVisitor { boolean isVarargs = (access & Opcodes.ACC_VARARGS) != 0; boolean isAnnotationMethod = myResult.isAnnotationType(); - if (!isConstructor && !isCorrectName(name)) return null; + if (!isConstructor && name == null) return null; - final byte flags = PsiMethodStubImpl.packFlags(isConstructor, isAnnotationMethod, isVarargs, isDeprecated, false, false); + byte flags = PsiMethodStubImpl.packFlags(isConstructor, isAnnotationMethod, isVarargs, isDeprecated, false, false); String canonicalMethodName = isConstructor ? myResult.getName() : name; List args = new ArrayList(); @@ -422,20 +361,20 @@ public class StubBuildingVisitor extends ClassVisitor { args = args.subList(2, args.size()); } - final boolean isNonStaticInnerClassConstructor = + boolean isNonStaticInnerClassConstructor = isConstructor && !(myParent instanceof PsiFileStub) && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0; boolean parsedViaGenericSignature = stub.isParsedViaGenericSignature(); - final boolean shouldSkipFirstParamForNonStaticInnerClassConstructor = !parsedViaGenericSignature && isNonStaticInnerClassConstructor; + boolean shouldSkipFirstParamForNonStaticInnerClassConstructor = !parsedViaGenericSignature && isNonStaticInnerClassConstructor; - final PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub); - final int paramCount = args.size(); - final PsiParameterStubImpl[] paramStubs = new PsiParameterStubImpl[paramCount]; + PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub); + int paramCount = args.size(); + PsiParameterStubImpl[] paramStubs = new PsiParameterStubImpl[paramCount]; for (int i = 0; i < paramCount; i++) { if (shouldSkipFirstParamForNonStaticInnerClassConstructor && i == 0) continue; String arg = args.get(i); boolean isEllipsisParam = isVarargs && i == paramCount - 1; - final TypeInfo typeInfo = TypeInfo.fromString(arg, isEllipsisParam); + TypeInfo typeInfo = TypeInfo.fromString(arg, isEllipsisParam); String paramName = i < parameterNames.length ? parameterNames[i] : "p" + (i + 1); PsiParameterStubImpl parameterStub = new PsiParameterStubImpl(parameterList, paramName, typeInfo, isEllipsisParam); @@ -475,8 +414,8 @@ public class StubBuildingVisitor extends ClassVisitor { @NotNull public static String parseMethodViaDescription(@NotNull String desc, @NotNull PsiMethodStubImpl stub, @NotNull List args) { - final String returnType = getTypeText(Type.getReturnType(desc)); - final Type[] argTypes = Type.getArgumentTypes(desc); + String returnType = getTypeText(Type.getReturnType(desc)); + Type[] argTypes = Type.getArgumentTypes(desc); for (Type argType : argTypes) { args.add(getTypeText(argType)); } @@ -522,11 +461,11 @@ public class StubBuildingVisitor extends ClassVisitor { private static class AnnotationTextCollector extends AnnotationVisitor { private final StringBuilder myBuilder = new StringBuilder(); - private final AnnotationResultCallback myCallback; + private final Consumer myCallback; private boolean hasParams = false; private final String myDesc; - public AnnotationTextCollector(@Nullable String desc, AnnotationResultCallback callback) { + public AnnotationTextCollector(@Nullable String desc, Consumer callback) { super(ASM_API); myCallback = callback; @@ -537,18 +476,18 @@ public class StubBuildingVisitor extends ClassVisitor { } @Override - public void visit(final String name, final Object value) { + public void visit(String name, Object value) { valuePairPrefix(name); myBuilder.append(constToString(value, null, true)); } @Override - public void visitEnum(final String name, final String desc, final String value) { + public void visitEnum(String name, String desc, String value) { valuePairPrefix(name); - myBuilder.append(getTypeText(Type.getType(desc))).append(".").append(value); + myBuilder.append(getTypeText(Type.getType(desc))).append('.').append(value); } - private void valuePairPrefix(final String name) { + private void valuePairPrefix(String name) { if (!hasParams) { hasParams = true; if (myDesc != null) { @@ -565,23 +504,23 @@ public class StubBuildingVisitor extends ClassVisitor { } @Override - public AnnotationVisitor visitAnnotation(final String name, final String desc) { + public AnnotationVisitor visitAnnotation(String name, String desc) { valuePairPrefix(name); - return new AnnotationTextCollector(desc, new AnnotationResultCallback() { + return new AnnotationTextCollector(desc, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { myBuilder.append(text); } }); } @Override - public AnnotationVisitor visitArray(final String name) { + public AnnotationVisitor visitArray(String name) { valuePairPrefix(name); - myBuilder.append("{"); - return new AnnotationTextCollector(null, new AnnotationResultCallback() { + myBuilder.append('{'); + return new AnnotationTextCollector(null, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { myBuilder.append(text).append('}'); } }); @@ -592,23 +531,23 @@ public class StubBuildingVisitor extends ClassVisitor { if (hasParams && myDesc != null) { myBuilder.append(')'); } - myCallback.callback(myBuilder.toString()); + myCallback.consume(myBuilder.toString()); } } private static class AnnotationCollectingVisitor extends FieldVisitor { private final PsiModifierListStub myModList; - private AnnotationCollectingVisitor(final PsiModifierListStub modList) { + private AnnotationCollectingVisitor(PsiModifierListStub modList) { super(ASM_API); myModList = modList; } @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - return new AnnotationTextCollector(desc, new AnnotationResultCallback() { + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new AnnotationTextCollector(desc, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); } }); @@ -627,9 +566,9 @@ public class StubBuildingVisitor extends ClassVisitor { private AnnotationParamCollectingVisitor(@NotNull PsiMethodStub owner, @NotNull PsiModifierListStub modList, - final int ignoreCount, - final int paramIgnoreCount, - final int paramCount, + int ignoreCount, + int paramIgnoreCount, + int paramCount, @NotNull PsiParameterStubImpl[] paramStubs) { super(ASM_API); myOwner = owner; @@ -641,10 +580,10 @@ public class StubBuildingVisitor extends ClassVisitor { } @Override - public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { - return new AnnotationTextCollector(desc, new AnnotationResultCallback() { + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return new AnnotationTextCollector(desc, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { new PsiAnnotationStubImpl(myModList, text); } }); @@ -652,9 +591,9 @@ public class StubBuildingVisitor extends ClassVisitor { @Override public AnnotationVisitor visitAnnotationDefault() { - return new AnnotationTextCollector(null, new AnnotationResultCallback() { + return new AnnotationTextCollector(null, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { ((PsiMethodStubImpl)myOwner).setDefaultValueText(text); } }); @@ -690,9 +629,9 @@ public class StubBuildingVisitor extends ClassVisitor { if (parameter < myParamIgnoreCount) { return null; } - return new AnnotationTextCollector(desc, new AnnotationResultCallback() { + return new AnnotationTextCollector(desc, new Consumer() { @Override - public void callback(final String text) { + public void consume(String text) { new PsiAnnotationStubImpl(myOwner.findParameter(parameter - myParamIgnoreCount).getModList(), text); } }); @@ -716,7 +655,7 @@ public class StubBuildingVisitor extends ClassVisitor { } if (value instanceof Long) { - return value.toString() + "L"; + return value.toString() + 'L'; } if (value instanceof Integer) { @@ -732,7 +671,7 @@ public class StubBuildingVisitor extends ClassVisitor { } if (value instanceof Double) { - final double d = (Double)value; + double d = (Double)value; if (Double.isInfinite(d)) { return d > 0 ? DOUBLE_POSITIVE_INF : DOUBLE_NEGATIVE_INF; } @@ -743,7 +682,7 @@ public class StubBuildingVisitor extends ClassVisitor { } if (value instanceof Float) { - final float v = (Float)value; + float v = (Float)value; if (Float.isInfinite(v)) { return v > 0 ? FLOAT_POSITIVE_INF : FLOAT_NEGATIVE_INF; @@ -752,7 +691,7 @@ public class StubBuildingVisitor extends ClassVisitor { return FLOAT_NAN; } else { - return Float.toString(v) + "f"; + return Float.toString(v) + 'f'; } } @@ -774,17 +713,13 @@ public class StubBuildingVisitor extends ClassVisitor { return null; } - private interface AnnotationResultCallback { - void callback(String text); - } - - private static String getClassName(final String name) { + private static String getClassName(String name) { return getTypeText(Type.getObjectType(name)); } @NotNull private static String getTypeText(@NotNull Type type) { - final String raw = type.getClassName(); + String raw = type.getClassName(); // As the '$' char is a valid java identifier and is actively used by byte code generators, the problem is // which occurrences of this char should be replaced and which should not. // Heuristic: replace only those $ occurrences that are surrounded non-"$" chars @@ -792,4 +727,4 @@ public class StubBuildingVisitor extends ClassVisitor { // Leading and trailing $ chars should be left unchanged. return raw.indexOf('$') >= 0 ? REGEX_PATTERN.matcher(raw).replaceAll("\\.") : raw; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassInitializerStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassInitializerStubImpl.java index 2fc4983786e0..457ca0515374 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassInitializerStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassInitializerStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiClassInitializer; @@ -25,6 +21,9 @@ import com.intellij.psi.impl.java.stubs.PsiClassInitializerStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +/** + * @author max + */ public class PsiClassInitializerStubImpl extends StubBase implements PsiClassInitializerStub { public PsiClassInitializerStubImpl(final StubElement parent) { super(parent, JavaStubElementTypes.CLASS_INITIALIZER); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java index 73d0f5304a45..24e7c656442f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiClassReferenceListStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.*; @@ -33,6 +29,9 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.io.StringRef; +/** + * @author max + */ public class PsiClassReferenceListStubImpl extends StubBase implements PsiClassReferenceListStub { private final PsiReferenceList.Role myRole; private final StringRef[] myNames; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportListStubImpl.java index 6f275a481298..e1382e546728 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportListStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiImportList; @@ -25,6 +21,9 @@ import com.intellij.psi.impl.java.stubs.PsiImportListStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +/** + * @author max + */ public class PsiImportListStubImpl extends StubBase implements PsiImportListStub { public PsiImportListStubImpl(final StubElement parent) { super(parent, JavaStubElementTypes.IMPORT_LIST); @@ -32,8 +31,6 @@ public class PsiImportListStubImpl extends StubBase implements Ps @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("PsiImportListStub"); - return builder.toString(); + return "PsiImportListStub"; } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportStatementStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportStatementStubImpl.java index 65c60197491c..699946cb81ce 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportStatementStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiImportStatementStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.JavaPsiFacade; @@ -33,6 +29,9 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.Nullable; +/** + * @author max + */ public class PsiImportStatementStubImpl extends StubBase implements PsiImportStatementStub { private final byte myFlags; private final StringRef myText; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java index b8c7f14930df..2b9f44090593 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiMethod; @@ -35,6 +31,9 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +/** + * @author max + */ public class PsiMethodStubImpl extends StubBase implements PsiMethodStub { private final TypeInfo myReturnType; private final byte myFlags; @@ -212,4 +211,4 @@ public class PsiMethodStubImpl extends StubBase implements PsiMethodS builder.append("]"); return builder.toString(); } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiModifierListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiModifierListStubImpl.java index 0980c9a3e1f4..e238b4a2c661 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiModifierListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiModifierListStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiModifierList; @@ -25,6 +21,9 @@ import com.intellij.psi.impl.java.stubs.PsiModifierListStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +/** + * @author max + */ public class PsiModifierListStubImpl extends StubBase implements PsiModifierListStub { private final int myMask; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterListStubImpl.java index e6f29b2db092..cfc3aa550a2a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterListStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiParameterList; @@ -25,6 +21,9 @@ import com.intellij.psi.impl.java.stubs.PsiParameterListStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +/** + * @author max + */ public class PsiParameterListStubImpl extends StubBase implements PsiParameterListStub { public PsiParameterListStubImpl(final StubElement parent) { super(parent, JavaStubElementTypes.PARAMETER_LIST); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterListStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterListStubImpl.java index a71fb7475563..9fbffcc6fc05 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterListStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterListStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiTypeParameterList; @@ -25,6 +21,9 @@ import com.intellij.psi.impl.java.stubs.PsiTypeParameterListStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +/** + * @author max + */ public class PsiTypeParameterListStubImpl extends StubBase implements PsiTypeParameterListStub{ public PsiTypeParameterListStubImpl(final StubElement parent) { super(parent, JavaStubElementTypes.TYPE_PARAMETER_LIST); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterStubImpl.java index 4f2a83519025..a315c3ad4ac6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiTypeParameterStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiTypeParameter; @@ -32,6 +28,9 @@ import org.jetbrains.annotations.NotNull; import java.util.List; +/** + * @author max + */ public class PsiTypeParameterStubImpl extends StubBase implements PsiTypeParameterStub { private final StringRef myName; @@ -47,9 +46,7 @@ public class PsiTypeParameterStubImpl extends StubBase impleme @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("PsiTypeParameter[").append(myName).append(']'); - return builder.toString(); + return "PsiTypeParameter[" + myName + ']'; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index e5b9763c41d7..e1531c92dc90 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index b120d5dfac12..7e213cd0bbf2 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -24,6 +24,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.constraints.StrictSub import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeCompatibilityConstraint; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Processor; import java.util.*; @@ -182,7 +183,7 @@ public class InferenceIncorporationPhase { private static Boolean isInferenceVariableOrFreshTypeParameter(PsiType eqBound) { final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(eqBound); if (psiClass instanceof InferenceVariable || - psiClass instanceof PsiTypeParameter && InferenceSession.isFreshVariable((PsiTypeParameter)psiClass)) return true; + psiClass instanceof PsiTypeParameter && TypeConversionUtil.isFreshVariable((PsiTypeParameter)psiClass)) return true; return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index b64ba29df4fc..4c9ca46acde3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -42,7 +42,6 @@ public class InferenceSession { private static final Logger LOG = Logger.getInstance("#" + InferenceSession.class.getName()); public static final Key LOWER_BOUND = Key.create("LowBound"); public static final Key UPPER_BOUND = Key.create("UpperBound"); - private static final Key ORIGINAL_CONTEXT = Key.create("ORIGINAL_CONTEXT"); private static final Key ERASED = Key.create("UNCHECKED_CONVERSION"); private static final Function, PsiType> UPPER_BOUND_FUNCTION = new Function, PsiType>() { @Override @@ -1038,7 +1037,7 @@ public class InferenceSession { } parameter.putUserData(UPPER_BOUND, composeBound(var, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(substitutor), true)); - parameter.putUserData(ORIGINAL_CONTEXT, myContext); + TypeConversionUtil.markAsFreshVariable(parameter, myContext); if (!var.addBound(elementFactory.createType(parameter), InferenceBound.EQ)) { return false; } @@ -1507,7 +1506,7 @@ public class InferenceSession { LOG.assertTrue(parameters1.length == parameters2.length); } - final int paramsLength = !varargs ? parameters1.length : parameters1.length - 1; + final int paramsLength = !varargs ? parameters1.length : Math.max(parameters1.length, parameters2.length) - 1; for (int i = 0; i < paramsLength; i++) { PsiType sType = getParameterType(parameters1, i, siteSubstitutor1, false); PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, i, siteSubstitutor1, varargs)); @@ -1768,15 +1767,6 @@ public class InferenceSession { return s.substitute(type); } - public static boolean areSameFreshVariables(PsiTypeParameter p1, PsiTypeParameter p2) { - final PsiElement originalContext = p1.getUserData(ORIGINAL_CONTEXT); - return originalContext != null && originalContext == p2.getUserData(ORIGINAL_CONTEXT); - } - - public static boolean isFreshVariable(PsiTypeParameter typeParameter) { - return typeParameter.getUserData(ORIGINAL_CONTEXT) != null; - } - public static PsiClass findParameterizationOfTheSameGenericClass(List upperBounds, Processor> processor) { for (int i = 0; i < upperBounds.size(); i++) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java index 39484a509d58..4ca48d1c0f6e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java @@ -198,18 +198,32 @@ public class InferenceSessionContainer { if (parent instanceof PsiCall) { break; } - if (parent instanceof PsiCodeBlock && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class) == null) { - break; - } - if (parent instanceof PsiLambdaExpression) { - boolean inReturnExpressions = false; - for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)parent)) { - inReturnExpressions |= PsiTreeUtil.isAncestor(expression, context, false); - } - if (!inReturnExpressions) { + + final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class); + if (parent instanceof PsiCodeBlock) { + if (lambdaExpression == null) { break; } + else { + boolean inReturnExpressions = false; + for (PsiExpression expression : LambdaUtil.getReturnExpressions(lambdaExpression)) { + inReturnExpressions |= PsiTreeUtil.isAncestor(expression, context, false); + } + + if (!inReturnExpressions) { + break; + } + + if (LambdaUtil.getFunctionalTypeMap().containsKey(lambdaExpression)) { + break; + } + } } + + if (parent instanceof PsiLambdaExpression && LambdaUtil.getFunctionalTypeMap().containsKey(parent)) { + break; + } + final PsiCall psiCall = PsiTreeUtil.getParentOfType(parent, PsiCall.class); if (psiCall == null) { break; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index 9c8ce5882286..523c7daf86b1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; @@ -118,12 +117,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai final List thrownTypes = new ArrayList(); final PsiElement body = myExpression instanceof PsiLambdaExpression ? ((PsiLambdaExpression)myExpression).getBody() : myExpression; if (body != null) { - final List exceptions = ExceptionUtil.ourThrowsGuard.doPreventingRecursion(myExpression, false, new Computable>() { - @Override - public List compute() { - return ExceptionUtil.getUnhandledExceptions(new PsiElement[] {body}); - } - }); + final List exceptions = ExceptionUtil.getUnhandledExceptions(new PsiElement[] {body}); if (exceptions != null) { thrownTypes.addAll(ContainerUtil.filter(exceptions, new Condition() { @Override diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CodeBlockLambdaWithIsValueCompatibleChecks.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CodeBlockLambdaWithIsValueCompatibleChecks.java new file mode 100644 index 000000000000..f5fb284da5e2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CodeBlockLambdaWithIsValueCompatibleChecks.java @@ -0,0 +1,23 @@ +import java.util.Optional; + +class Test { + public static void main(String[] args) { + Optional> eith = + Optional.of(new Either()); + + eith.map(either -> { + String foo = Test.foo(either); + return foo; + }).orElse("Hello"); + + eith.map(either -> { + return Test.foo(either); + }).orElse("Hello"); + + eith.map(either -> Test.foo(either)).orElse("Hello"); + } + + private static A foo(Either either) throws X { return null; } +} + +class Either { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/LongerParamsWhenVarargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/LongerParamsWhenVarargs.java new file mode 100644 index 000000000000..57b52d91d23a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/LongerParamsWhenVarargs.java @@ -0,0 +1,21 @@ +interface Node<T> { + + @SafeVarargs + static Node of(T value, Node... children) { + System.out.println(value); + System.out.println(children); + return null; + } + + + @SafeVarargs + static Node of(T1... values) { + System.out.println(values); + return null; + } + + static void test() { + Node.of(1, Node.of(2), Node.of(3)); + Node.of(1, Node.of(2), Node. of(3)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterBlockLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterBlockLambda.java new file mode 100644 index 000000000000..c5fc4f967c50 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterBlockLambda.java @@ -0,0 +1,9 @@ +// "Replace method call on lambda with lambda body" "true" +import java.util.function.Supplier; + +class Test { + { + String s = ""; + String str = s; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterExprLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterExprLambda.java new file mode 100644 index 000000000000..b63be02a9295 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterExprLambda.java @@ -0,0 +1,6 @@ +// "Replace method call on lambda with lambda body" "true" +import java.util.function.Supplier; + +class Test { + String s = ""; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterMethodRef.java new file mode 100644 index 000000000000..bd2262d5df9b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/afterMethodRef.java @@ -0,0 +1,10 @@ +// "Replace method call on method reference with corresponding method call" "true" +import java.util.function.Supplier; + +class Test { + String s = foo(); + + private String foo() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambda.java new file mode 100644 index 000000000000..e920715c0f91 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambda.java @@ -0,0 +1,11 @@ +// "Replace method call on lambda with lambda body" "true" +import java.util.function.Supplier; + +class Test { + { + String str = ((Supplier)() -> { + String s = ""; + return s; + }).get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambdaInFieldDeclaration.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambdaInFieldDeclaration.java new file mode 100644 index 000000000000..714721e2826e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeBlockLambdaInFieldDeclaration.java @@ -0,0 +1,9 @@ +// "Replace method call on lambda with lambda body" "false" +import java.util.function.Supplier; + +class Test { + String str = ((Supplier) () -> { + String s = ""; + return s; + }).get(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeExprLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeExprLambda.java new file mode 100644 index 000000000000..8303b227f987 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeExprLambda.java @@ -0,0 +1,8 @@ +// "Replace method call on lambda with lambda body" "true" +import java.util.function.Supplier; + +class Test { + String s = ((Supplier) () -> { + return ""; + }).get(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeMethodRef.java new file mode 100644 index 000000000000..6368b6b8e1ca --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeMethodRef.java @@ -0,0 +1,10 @@ +// "Replace method call on method reference with corresponding method call" "true" +import java.util.function.Supplier; + +class Test { + String s = ((Supplier) this::foo).get(); + + private String foo() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeUnresolvedMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeUnresolvedMethodRef.java new file mode 100644 index 000000000000..47fd75c03525 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeUnresolvedMethodRef.java @@ -0,0 +1,6 @@ +// "Replace method call on method reference with corresponding method call" "false" +import java.util.function.Supplier; + +class Test { + String s = ((Supplier) this::foo).get(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicate.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicate.java new file mode 100644 index 000000000000..2e8598624932 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicate.java @@ -0,0 +1,8 @@ +// "Replace with qualifier" "true" +import java.util.function.Predicate; + +class Test { + void foo(Predicate p){ + Predicate stringPredicate = p; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicateInheritor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicateInheritor.java new file mode 100644 index 000000000000..311417295d5d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/afterPredicateInheritor.java @@ -0,0 +1,12 @@ +// "Replace with qualifier" "true" +import java.util.function.Predicate; + +class Test implements Predicate { + void foo(){ + Predicate stringPredicate = this; + } + + public boolean test(String s) { + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicate.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicate.java new file mode 100644 index 000000000000..67d9a0ac4203 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicate.java @@ -0,0 +1,8 @@ +// "Replace with qualifier" "true" +import java.util.function.Predicate; + +class Test { + void foo(Predicate p){ + Predicate stringPredicate = p::test; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicateInheritor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicateInheritor.java new file mode 100644 index 000000000000..2270c5685ba9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference/beforePredicateInheritor.java @@ -0,0 +1,12 @@ +// "Replace with qualifier" "true" +import java.util.function.Predicate; + +class Test implements Predicate { + void foo(){ + Predicate stringPredicate = this::test; + } + + public boolean test(String s) { + return true; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java new file mode 100644 index 000000000000..c522b20a52f2 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java @@ -0,0 +1,15 @@ +import java.util.function.Supplier; + +public class Test { + + public Test() { + this(0); + } + + public Test(int i) {} + + + { + Supplier sup = Test::new; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java.after b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java.after new file mode 100644 index 000000000000..34fbae24db7b --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoConstructorRef.java.after @@ -0,0 +1,15 @@ +import java.util.function.Supplier; + +public class Test { + + public Test() { + this(0); + } + + public Test(int i) {} + + + { + Supplier sup = () -> new Test(0); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java new file mode 100644 index 000000000000..762b0f595b7b --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java @@ -0,0 +1,11 @@ +import java.util.function.Supplier; + +class Test { + { + Supplier sup = this::get; + } + + private String get() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java.after b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java.after new file mode 100644 index 000000000000..2a7e11c5fe08 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/InlineIntoMethodRef.java.after @@ -0,0 +1,11 @@ +import java.util.function.Supplier; + +class Test { + { + Supplier sup = () -> null; + } + + private String get() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/SideEffectsInMethodRefQualifier.java b/java/java-tests/testData/refactoring/inlineMethod/SideEffectsInMethodRefQualifier.java new file mode 100644 index 000000000000..a138b39b60a1 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SideEffectsInMethodRefQualifier.java @@ -0,0 +1,13 @@ + +import java.util.function.Supplier; + +public class Test { + + { + Supplier sup = new Test()::get; + } + + private String get() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy.java b/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy.java new file mode 100644 index 000000000000..3f578b3425a2 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy.java @@ -0,0 +1,3 @@ +class A { + public <T> void foo() {} +} diff --git a/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy_after.java b/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy_after.java new file mode 100644 index 000000000000..0604b2502c29 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/TypeParameterNoMethodHierarchy_after.java @@ -0,0 +1,3 @@ +class A { + public void foo() {} +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index ff73bcfdb83f..d6188766f1b8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -264,6 +264,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testCodeBlockLambdaWithIsValueCompatibleChecks() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java index 5e7519b18e3e..41d03b6e7d23 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java @@ -195,6 +195,10 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testLongerParamsWhenVarargs() throws Exception { + doTest(); + } + private void doTest() { doTest(true); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialFunctionalExpressionUsageInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialFunctionalExpressionUsageInspectionTest.java new file mode 100644 index 000000000000..5de09e455807 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialFunctionalExpressionUsageInspectionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 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.quickFix; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.TrivialFunctionalExpressionUsageInspection; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NotNull; + + +public class TrivialFunctionalExpressionUsageInspectionTest extends LightQuickFixParameterizedTestCase { + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{ + new TrivialFunctionalExpressionUsageInspection(), + }; + } + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage"; + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialMethodReferenceInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialMethodReferenceInspectionTest.java new file mode 100644 index 000000000000..00263f77aab1 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/TrivialMethodReferenceInspectionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 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.quickFix; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.TrivialMethodReferenceInspection; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NotNull; + + +public class TrivialMethodReferenceInspectionTest extends LightQuickFixParameterizedTestCase { + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{ + new TrivialMethodReferenceInspection(), + }; + } + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/trivialMethodReference"; + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java index 280b8fd2b8ae..719a074891ef 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java @@ -280,6 +280,10 @@ public class SafeDeleteTest extends MultiFileTestCase { public void testTypeParameterWithinMethodHierarchy() throws Exception { doSingleFileTest(); } + + public void testTypeParameterNoMethodHierarchy() throws Exception { + doSingleFileTest(); + } public void testClassWithInnerStaticImport() throws Exception { doTest("ClassWithInnerStaticImport"); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java index 5b1e5a733c7b..ba6395fa993b 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java @@ -292,6 +292,18 @@ public class InlineMethodTest extends LightRefactoringTestCase { doTestInlineThisOnly(); } + public void testInlineIntoMethodRef() throws Exception { + doTestInlineThisOnly(); + } + + public void testInlineIntoConstructorRef() throws Exception { + doTestInlineThisOnly(); + } + + public void testSideEffectsInMethodRefQualifier() throws Exception { + doTestConflict("Inlined method is used in method reference with side effects in qualifier"); + } + private void doTestInlineThisOnly() { @NonNls String fileName = "/refactoring/inlineMethod/" + getTestName(false) + ".java"; configureByFile(fileName); diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java index d986896c3b8d..3987df0e2f26 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/FluentIterableConversionUtil.java @@ -29,12 +29,11 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; import com.intellij.refactoring.typeMigration.TypeEvaluator; +import com.intellij.refactoring.util.LambdaRefactoringUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SmartList; import com.intellij.util.text.UniqueNameGenerator; import com.siyeh.ig.psiutils.ParenthesesUtils; -import com.siyeh.ipp.types.ReplaceMethodRefWithLambdaIntention; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -157,7 +156,7 @@ public class FluentIterableConversionUtil { } if (argument instanceof PsiMethodReferenceExpression) { - argument = ReplaceMethodRefWithLambdaIntention.convertMethodReferenceToLambda((PsiMethodReferenceExpression)argument, true); + argument = LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)argument, true, true); } if (argument instanceof PsiLambdaExpression) { List> iterableReturnValues = new SmartList>(); diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java index dbb79921a2ec..2635b15893c6 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaFluentIterableConversionRule.java @@ -297,9 +297,15 @@ public class GuavaFluentIterableConversionRule extends BaseGuavaTypeConversionRu TypeConversionDescriptorBase descriptor = null; if (FLUENT_ITERABLE.equals(containingClass.getQualifiedName())) { descriptor = getOneMethodDescriptor(methodName, method, current.getType(), null, current); + if (descriptor == null) { + return null; + } } else if (GuavaOptionalConversionRule.GUAVA_OPTIONAL.equals(containingClass.getQualifiedName())) { descriptor = optionalDescriptor.getValue().findConversion(null, null, method, current.getMethodExpression(), labeler); + if (descriptor == null) { + return null; + } } if (descriptor == null) { addToMigrateChainQualifier(labeler, current); diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java index a7f9d0a1f850..32b434d04e7d 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicateConversionRule.java @@ -64,7 +64,7 @@ public class GuavaPredicateConversionRule extends GuavaLambdaConversionRule { return new TypeConversionDescriptorBase() { @Override public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException { - return (PsiExpression)expression.replace(JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::test", expression)); + return (PsiExpression)expression.replace(JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(expression.getText() + "::apply", expression)); } }; } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicatesUtil.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicatesUtil.java index bff50ba3da83..b24aa7c12ea3 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicatesUtil.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/guava/GuavaPredicatesUtil.java @@ -45,7 +45,7 @@ public class GuavaPredicatesUtil { static TypeConversionDescriptorBase tryConvertIfPredicates(PsiMethod method, PsiExpression context) { final String name = method.getName(); if (name.equals("alwaysTrue") || name.equals("alwaysFalse")) { - return new TypeConversionDescriptorWithLocalVariable(name, "$x$ -> " + name.contains("True") + ""); + return createConstantPredicate(name, name.contains("True")); } else if (name.equals("isNull") || name.equals("notNull")) { final String operation = name.equals("isNull") ? "==" : "!="; @@ -54,7 +54,10 @@ public class GuavaPredicatesUtil { else if (name.equals("equalTo")) { return new TypeConversionDescriptorWithLocalVariable("equalTo", "$x$ -> java.util.Objects.equals($x$, $v$)"); } - if (!isConvertablePredicatesMethod(method)) return null; + if (!isConvertablePredicatesMethod(method, (PsiMethodCallExpression)context)) return null; + if (((PsiMethodCallExpression)context).getArgumentList().getExpressions().length == 0) { + return createConstantPredicate(name, name.equals("and")); + } if (PREDICATES_AND_OR.contains(name) && canMigrateAndOrOr((PsiMethodCallExpression)context)) { return new AndOrOrConversionDescriptor(GuavaConversionUtil.addTypeParameters(GuavaLambda.PREDICATE.getJavaAnalogueClassQName(), context.getType(), context)); } @@ -64,6 +67,11 @@ public class GuavaPredicatesUtil { return null; } + @NotNull + private static TypeConversionDescriptorWithLocalVariable createConstantPredicate(String methodName, boolean value) { + return new TypeConversionDescriptorWithLocalVariable(methodName, "$x$ -> " + value + ""); + } + private static class TypeConversionDescriptorWithLocalVariable extends TypeConversionDescriptor { private final String myReplaceByStringTemplate; @@ -95,7 +103,7 @@ public class GuavaPredicatesUtil { } - public static boolean isConvertablePredicatesMethod(@NotNull PsiMethod method) { + public static boolean isConvertablePredicatesMethod(@NotNull PsiMethod method, PsiMethodCallExpression context) { if (method.getParameterList().getParametersCount() == 1) { final PsiParameter parameter = method.getParameterList().getParameters()[0]; final PsiClass psiClass = PsiTypesUtil.getPsiClass(parameter.getType().getDeepComponentType()); @@ -103,7 +111,8 @@ public class GuavaPredicatesUtil { return false; } } - return true; + final PsiExpression[] expressions = context.getArgumentList().getExpressions(); + return !(expressions.length == 1 && expressions[0].getType() instanceof PsiArrayType); } private static boolean canMigrateAndOrOr(PsiMethodCallExpression expr) { diff --git a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java index de1e374d238b..480a17c124be 100644 --- a/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java +++ b/java/typeMigration/test/com/intellij/codeInsight/inspections/GuavaInspectionTest.java @@ -255,6 +255,10 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase { doTestAllFile(); } + public void testFluentIterableElementTypeChanged() { + doTest(); + } + private void doTestNoQuickFixes(Class... highlightedElements) { myFixture.configureByFile(getTestName(true) + ".java"); myFixture.enableInspections(new GuavaInspection()); diff --git a/java/typeMigration/test/com/intellij/refactoring/MigrateTypeSignatureTest.java b/java/typeMigration/test/com/intellij/refactoring/MigrateTypeSignatureTest.java index 328b8462fed0..464d76bf41cb 100644 --- a/java/typeMigration/test/com/intellij/refactoring/MigrateTypeSignatureTest.java +++ b/java/typeMigration/test/com/intellij/refactoring/MigrateTypeSignatureTest.java @@ -522,7 +522,7 @@ public class MigrateTypeSignatureTest extends TypeMigrationTestBase { final PsiType toType) { final RulesProvider provider = new RulesProvider() { @Override - public PsiType migrationType() throws Exception { + public PsiType migrationType(PsiElement context) throws Exception { return toType; } diff --git a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java index 91d31a03b869..da90f6f7bd93 100644 --- a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java +++ b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java @@ -709,7 +709,7 @@ public class TypeMigrationTest extends TypeMigrationTestBase { private void doTestCatchParameter(final PsiType rootType, final PsiType migrationType) { start(new RulesProvider() { @Override - public PsiType migrationType() { + public PsiType migrationType(PsiElement context) { return migrationType; } @@ -807,7 +807,7 @@ public class TypeMigrationTest extends TypeMigrationTestBase { } public void testMethodReturnTypeWithTypeParameter() { - doTestReturnType("meth", myFactory.createTypeFromText("java.util.List", null)); + doTestReturnType("meth", "java.util.List"); } public void testBooleanGetterMethodName() { @@ -826,11 +826,11 @@ public class TypeMigrationTest extends TypeMigrationTestBase { doTestFieldType("fooDontMigrateName", PsiType.BOOLEAN); } - private void doTestReturnType(final String methodName, final PsiType migrationType) { + private void doTestReturnType(final String methodName, final String migrationType) { start(new RulesProvider() { @Override - public PsiType migrationType() throws Exception { - return migrationType; + public PsiType migrationType(PsiElement context) throws Exception { + return myFactory.createTypeFromText(migrationType, context); } @Override @@ -848,7 +848,7 @@ public class TypeMigrationTest extends TypeMigrationTestBase { private void doTestForeachParameter(final PsiType migrationType) { start(new RulesProvider() { @Override - public PsiType migrationType() { + public PsiType migrationType(PsiElement context) { return migrationType; } diff --git a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java index 43ee0cc7702e..889511a5670e 100644 --- a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java +++ b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java @@ -57,7 +57,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { final PsiType toType) { final RulesProvider provider = new RulesProvider() { @Override - public PsiType migrationType() throws Exception { + public PsiType migrationType(PsiElement context) throws Exception { return toType; } @@ -84,7 +84,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { protected void doTestFieldType(@NonNls final String fieldName, String className, final PsiType migrationType) { final RulesProvider provider = new RulesProvider() { @Override - public PsiType migrationType() throws Exception { + public PsiType migrationType(PsiElement context) throws Exception { return migrationType; } @@ -108,7 +108,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { final PsiType migrationType) { final RulesProvider provider = new RulesProvider() { @Override - public PsiType migrationType() throws Exception { + public PsiType migrationType(PsiElement context) throws Exception { return migrationType; } @@ -128,7 +128,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { protected void doTestFirstParamType(@NonNls final String methodName, String className, final PsiType migrationType) { final RulesProvider provider = new RulesProvider() { @Override - public PsiType migrationType() throws Exception { + public PsiType migrationType(PsiElement context) throws Exception { return migrationType; } @@ -159,10 +159,11 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { assertNotNull("Class " + className + " not found", aClass); - final PsiType migrationType = provider.migrationType(); + final PsiElement migrationElement = provider.victims(aClass); + final PsiType migrationType = provider.migrationType(migrationElement); final TypeMigrationRules rules = new TypeMigrationRules(); rules.setBoundScope(new LocalSearchScope(aClass.getContainingFile())); - final TestTypeMigrationProcessor pr = new TestTypeMigrationProcessor(getProject(), provider.victims(aClass), migrationType, rules); + final TestTypeMigrationProcessor pr = new TestTypeMigrationProcessor(getProject(), migrationElement, migrationType, rules); final UsageInfo[] usages = pr.findUsages(); final String report = pr.getLabeler().getMigrationReport(); @@ -210,7 +211,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { } interface RulesProvider { - PsiType migrationType() throws Exception; + PsiType migrationType(PsiElement context) throws Exception; PsiElement victims(PsiClass aClass); } diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged.java b/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged.java new file mode 100644 index 000000000000..5f0f8693e51f --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged.java @@ -0,0 +1,10 @@ +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; + +import java.util.List; + +public class FluentTransformer { + public FluentIterable transformGeneric(FluentIterable p1, Function p2) { + return p1.transform(p2); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged_after.java b/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged_after.java new file mode 100644 index 000000000000..567a62ebcbf1 --- /dev/null +++ b/java/typeMigration/testData/inspections/guava/fluentIterableElementTypeChanged_after.java @@ -0,0 +1,9 @@ +import com.google.common.base.Function; + +import java.util.stream.Stream; + +public class FluentTransformer { + public Stream transformGeneric(Stream p1, Function p2) { + return p1.map(p2::apply); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/t17/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/t17/after/Test.items index aa0aa0551659..59b74e1b30bb 100644 --- a/java/typeMigration/testData/refactoring/typeMigration/t17/after/Test.items +++ b/java/typeMigration/testData/refactoring/typeMigration/t17/after/Test.items @@ -1,18 +1,11 @@ Types: PsiField:f : B -PsiMethodCallExpression:f.foo(s) : B -PsiMethodCallExpression:s.add(f) : boolean -PsiParameter:s : java.util.Set +PsiMethodCallExpression:f.foo(s) : A PsiReferenceExpression:f : B PsiReferenceExpression:f : B -PsiReferenceExpression:s : java.util.Set -PsiReferenceExpression:s : java.util.Set Conversions: -f -> $ f.foo(s) -> $ -s -> $ -s.add(f) -> $ New expression type changes: Fails: diff --git a/java/typeMigration/testData/refactoring/typeMigration/t17/after/test.java b/java/typeMigration/testData/refactoring/typeMigration/t17/after/test.java index 73530057f21b..d90d101faed2 100644 --- a/java/typeMigration/testData/refactoring/typeMigration/t17/after/test.java +++ b/java/typeMigration/testData/refactoring/typeMigration/t17/after/test.java @@ -2,7 +2,7 @@ import java.util.*; class Test { B f; - A bar(Set s) { + A bar(Set s) { s.add(f); return f.foo(s); } diff --git a/java/typeMigration/testData/refactoring/typeMigration/t93/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/t93/after/Test.items index ea2fc9440478..aaa26f9139cb 100644 --- a/java/typeMigration/testData/refactoring/typeMigration/t93/after/Test.items +++ b/java/typeMigration/testData/refactoring/typeMigration/t93/after/Test.items @@ -1,11 +1,8 @@ Types: -PsiField:f : java.util.Map PsiParameter:b : boolean PsiReferenceExpression:b : boolean -PsiReferenceExpression:f : java.util.Map Conversions: -f -> $ New expression type changes: Fails: diff --git a/platform/built-in-server/built-in-server-tests.iml b/platform/built-in-server/built-in-server-tests.iml index 1ee2004f04e2..b5a8959c65f0 100644 --- a/platform/built-in-server/built-in-server-tests.iml +++ b/platform/built-in-server/built-in-server-tests.iml @@ -1,6 +1,6 @@ - + @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/platform/built-in-server/built-in-server.iml b/platform/built-in-server/built-in-server.iml index a49a37419e3b..1d39586de48e 100644 --- a/platform/built-in-server/built-in-server.iml +++ b/platform/built-in-server/built-in-server.iml @@ -1,11 +1,9 @@ - + - - diff --git a/platform/built-in-server/client/.gitignore b/platform/built-in-server/client/.gitignore index fee741232909..e31ba3b844e9 100644 --- a/platform/built-in-server/client/.gitignore +++ b/platform/built-in-server/client/.gitignore @@ -1,3 +1,4 @@ node_modules/ npm-debug.log -out/ \ No newline at end of file +out/ +.idea/ \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/.npmignore b/platform/built-in-server/client/node-rpc-client/.npmignore new file mode 100644 index 000000000000..b81bb34ca62a --- /dev/null +++ b/platform/built-in-server/client/node-rpc-client/.npmignore @@ -0,0 +1,6 @@ +src/ +test/ +node-rpc-client.iml +typings/node/ +tsconfig.json +tsd.json \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/LICENSE b/platform/built-in-server/client/node-rpc-client/LICENSE new file mode 100644 index 000000000000..63cb0f0363c5 --- /dev/null +++ b/platform/built-in-server/client/node-rpc-client/LICENSE @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 JetBrains + + 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. + \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/node-rpc-client.iml b/platform/built-in-server/client/node-rpc-client/node-rpc-client.iml index 80cc7391bd40..3b9278ee9a90 100644 --- a/platform/built-in-server/client/node-rpc-client/node-rpc-client.iml +++ b/platform/built-in-server/client/node-rpc-client/node-rpc-client.iml @@ -2,7 +2,11 @@ - + + + + + \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/package.json b/platform/built-in-server/client/node-rpc-client/package.json index 2f5c4fbc836d..3aca753b69d2 100644 --- a/platform/built-in-server/client/node-rpc-client/package.json +++ b/platform/built-in-server/client/node-rpc-client/package.json @@ -2,8 +2,10 @@ "name": "ij-rpc-client", "version": "0.0.1", "description": "IntelliJ Platform RPC client", + "license": "Apache-2.0", + "main": "./out/rpc-node.js", "scripts": { - "compile": "rimraf app/out && tsconfig -i 2 && tsc", + "compile": "rimraf out && tsconfig -i 2 && tsc", "test": "mocha --harmony_default_parameters --harmony_rest_parameters" }, "repository": { @@ -11,12 +13,15 @@ "url": "https://github.com/JetBrains/intellij-community.git" }, "devDependencies": { + "dts-generator": "^1.6.3", + "mocha": "^2.3.4", "rimraf": "^2.5.0", "should": "^8.0.2", "tsconfig-glob": "^0.3.3", "typescript": "^1.8.0-dev.20151231" }, "dependencies": { - "bluebird": "^3.1.1" + "bluebird": "^3.1.1", + "debug": "^2.2.0" } } diff --git a/platform/built-in-server/client/node-rpc-client/src/rpc-client.ts b/platform/built-in-server/client/node-rpc-client/src/rpc-client.ts deleted file mode 100644 index 45343ddd758c..000000000000 --- a/platform/built-in-server/client/node-rpc-client/src/rpc-client.ts +++ /dev/null @@ -1,139 +0,0 @@ -import * as net from "net" -import { JsonRpc, Transport } from "./rpc" - -export class RpcClient { - connect(port: number = 63342) { - const socket = net.connect({port: port}, () => { - console.log("Connected to IJ RPC server localhost: " + port) - }) - - const transport = new SocketTransport(socket) - const jsonRpc = new JsonRpc(transport) - const decoder = new MessageDecoder(jsonRpc.messageReceived) - socket.on("data", decoder.messageReceived) - } -} - -const enum State {LENGTH, CONTENT} - -export class SocketTransport implements Transport { - private headerBuffer = new Buffer(4) - - opened: () => void - - constructor(private socket: net.Socket = new net.Socket()) { - } - - connect(port: number = 63342) { - this.socket.connect(port, null, ()=> { - const opened = this.opened - if (opened != null) { - opened() - } - }) - this.socket.on("error", (e: Error) => { - console.error(e) - }) - this.socket.write(new Buffer([67, 72, 105, -107, 126, -21, -81, -72, 64, 54, -87, -88, 0, -46, -48, 34, -7, -67])) - } - - send(id: number, domain: string, command: string, params: any[] = null): void { - const encodedParams = JSON.stringify(params) - const header = (id == -1 ? '' : (id + ', ')) + '"' + domain + '", "' + command + '"'; - this.headerBuffer.writeUInt32BE(header.length + Buffer.byteLength(encodedParams), 0) - this.socket.write(this.headerBuffer) - this.socket.write(header) - this.socket.write(encodedParams) - } - - sendResult(id: number, result: any): void { - this.sendResultOrError(id, result, false) - } - - sendError(id: number, error: any): void { - this.sendResultOrError(id, error, true) - } - - private sendResultOrError(id: number, result: any, isError: boolean): void { - var encodedResult = JSON.stringify(result) - var header = id + ', "' + (isError ? 'e' : 'r') + '"'; - this.headerBuffer.writeUInt32BE(Buffer.byteLength(encodedResult) + header.length, 0) - this.socket.write(this.headerBuffer) - this.socket.write(encodedResult) - } -} - -class MessageDecoder { - private state: State = State.LENGTH - private contentLength: number = 0 - - private buffers: Array = [] - private totalBufferLength: number = 0 - private offset: number = 0 - - constructor(private messageProcessor: (message: any)=>void) { - } - - private byteConsumed(count: number) { - this.offset += count - this.totalBufferLength -= count - } - - messageReceived(buffer: Buffer) { - this.totalBufferLength += buffer.length - - while (true) { - //noinspection FallThroughInSwitchStatementJS - switch (this.state) { - case State.LENGTH: - { - if (this.totalBufferLength < 4) { - this.buffers.push(buffer) - return - } - - var totalBuffer: Buffer - if (this.buffers.length === 0) { - totalBuffer = buffer - } - else { - this.buffers.push(buffer) - totalBuffer = Buffer.concat(this.buffers, this.totalBufferLength) - this.buffers.length = 0 - } - - this.state = State.CONTENT - this.contentLength = totalBuffer.readUInt32BE(this.offset) - this.byteConsumed(4) - buffer = totalBuffer - } - - case State.CONTENT: - { - if (this.totalBufferLength < this.contentLength) { - this.buffers.push(buffer) - return - } - - var totalBuffer: Buffer - if (this.buffers.length === 0) { - totalBuffer = buffer - } - else { - this.buffers.push(buffer) - totalBuffer = Buffer.concat(this.buffers, this.totalBufferLength) - this.buffers.length = 0 - } - - var message = JSON.parse(totalBuffer.toString('utf8', this.offset, this.contentLength)); - this.state = State.LENGTH - this.byteConsumed(this.contentLength) - this.contentLength = 0 - buffer = totalBuffer - - this.messageProcessor(message) - } - } - } - } -} \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/src/rpc-node.ts b/platform/built-in-server/client/node-rpc-client/src/rpc-node.ts new file mode 100644 index 000000000000..84f336047cc8 --- /dev/null +++ b/platform/built-in-server/client/node-rpc-client/src/rpc-node.ts @@ -0,0 +1,173 @@ +import * as net from "net" +import { JsonRpc, Transport } from "./rpc" +const debug = require("debug")("rpc") + +export function connect(port: number = 63342, domains: { [domainName:string]: { [methodName:string]:Function; }; } = null): JsonRpc { + const transport = new SocketTransport() + const server = new JsonRpc(transport, domains) + transport.connect(port) + return server +} + +export class SocketTransport implements Transport { + opened: () => void + messageReceived: (message: Array) => void + + constructor(private socket: net.Socket = new net.Socket()) { + } + + connect(port: number = 63342) { + this.socket.connect(port, null, ()=> { + debug("Connected to %s", port) + const opened = this.opened + if (opened != null) { + opened() + } + }) + this.socket.on("error", (e: Error) => { + console.error(e) + }) + + const messageReceived = this.messageReceived + if (messageReceived == null) { + console.warn("messageReceived is not specified, input will be ignored") + } + else { + const messageDecoder = new MessageDecoder(messageReceived) + this.socket.on("data", messageDecoder.messageReceived.bind(messageDecoder)) + } + + this.socket.write(new Buffer([67, 72, 105, -107, 126, -21, -81, -72, 64, 54, -87, -88, 0, -46, -48, 34, -7, -67])) + } + + send(id: number, domain: string, command: string, params: any[] = null): void { + const encodedParams = params == null || params.length === 0 ? null : JSON.stringify(params) + const header = '[' + (id == -1 ? '' : (id + ', ')) + '"' + domain + '", "' + command + '"' + const headerBuffer = new Buffer(4) + headerBuffer.writeUInt32BE(header.length + (encodedParams == null ? 0 : Buffer.byteLength(encodedParams)) + 1 /* ] symbol*/, 0) + this.socket.write(headerBuffer) + + debug("out: %s%s]", header, encodedParams || "") + + this.socket.write(header) + if (encodedParams != null) { + this.socket.write(encodedParams) + } + this.socket.write(']') + } + + sendResult(id: number, result: any): void { + this.sendResultOrError(id, result, false) + } + + sendError(id: number, error: any): void { + this.sendResultOrError(id, error, true) + } + + private sendResultOrError(id: number, result: any, isError: boolean): void { + var encodedResult = JSON.stringify(result) + var header = id + ', "' + (isError ? 'e' : 'r') + '"' + const headerBuffer = new Buffer(4) + headerBuffer.writeUInt32BE(Buffer.byteLength(encodedResult) + header.length, 0) + this.socket.write(headerBuffer) + this.socket.write(encodedResult) + } +} + +const enum State {LENGTH, CONTENT} + +class MessageDecoder { + private state = State.LENGTH + private contentLength = 0 + + private buffers: Array = [] + private messageBuffer: Buffer + + private readableByteCount = 0 + + private messageBufferOffset = 0 + + constructor(private messageProcessor: (message: any)=>void) { + } + + private concatBuffer(buffer: Buffer): Buffer { + if (this.buffers.length === 0) { + return buffer + } + + this.buffers.push(buffer) + let totalBuffer = Buffer.concat(this.buffers, this.readableByteCount) + this.buffers.length = 0 + return totalBuffer + } + + messageReceived(buffer: Buffer) { + let offset = 0 + this.readableByteCount += buffer.length + while (true) { + //noinspection FallThroughInSwitchStatementJS + switch (this.state) { + case State.LENGTH: { + if (this.readableByteCount < 4) { + if (offset != 0) { + buffer = buffer.slice(offset) + } + this.buffers.push(buffer) + return + } + + buffer = this.concatBuffer(buffer) + this.state = State.CONTENT + this.contentLength = buffer.readUInt32BE(offset) + offset += 4 + + if ((buffer.length - offset) < this.contentLength) { + this.messageBuffer = new Buffer(this.contentLength) + buffer.copy(this.messageBuffer, 0, offset) + this.messageBufferOffset = 0 + this.readableByteCount = 0 + return + } + + this.readableByteCount = buffer.length - offset + } + + case State.CONTENT: { + let rawMessage: string + if (this.messageBuffer == null) { + rawMessage = buffer.toString("utf8", offset, offset + this.contentLength) + offset += this.contentLength + this.readableByteCount = buffer.length - offset + } + else { + const requiredByteCount = this.messageBuffer.length - this.messageBufferOffset + if (requiredByteCount > this.readableByteCount) { + buffer.copy(this.messageBuffer, this.messageBufferOffset, offset) + this.messageBufferOffset += this.readableByteCount + this.readableByteCount = 0 + return + } + else { + const newOffset = offset + requiredByteCount + buffer.copy(this.messageBuffer, this.messageBufferOffset, offset, newOffset) + offset = newOffset + this.readableByteCount = buffer.length - offset + rawMessage = this.messageBuffer.toString("utf8") + } + } + + debug("in: %s", rawMessage) + try { + this.state = State.LENGTH + this.contentLength = 0 + + this.messageProcessor(JSON.parse(rawMessage)) + } + catch (e) { + console.error("Error: %s,\nInput: %s", e, rawMessage) + } + } + } + } + } +} \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/src/rpc.ts b/platform/built-in-server/client/node-rpc-client/src/rpc.ts index 7aba41a980da..40f5fca7cc2e 100644 --- a/platform/built-in-server/client/node-rpc-client/src/rpc.ts +++ b/platform/built-in-server/client/node-rpc-client/src/rpc.ts @@ -8,6 +8,11 @@ class PromiseCallback { export interface Transport { opened?: () => void + /** + * Internal use only (JsonRpc configure it). + */ + messageReceived: (message: Array) => void + connect(port: number): void send(id: number, domain: string, command: string, params: any[]): void @@ -17,26 +22,57 @@ export interface Transport { sendError(id: number, error: any):void } +interface Map { + clear(): void; + delete(key: K): boolean; + get(key: K): V; + has(key: K): boolean; + set(key: K, value?: V): Map; +} + +interface MapConstructor { + new (): Map + + prototype: Map +} +declare var Map: MapConstructor + export class JsonRpc { private messageIdCounter = 0 private callbacks: Map = new Map() - private domains: Map = new Map() + private domains = new Map() - constructor(private transport: Transport) { + constructor(private transport: Transport, domains: { [domainName:string]: { [methodName:string]:Function; }; } = null) { + this.domains = new Map() + if (domains != null) { + for (let name of Object.getOwnPropertyNames(domains)) { + this.domains.set(name, domains[name]) + } + } + + transport.messageReceived = this.messageReceived.bind(this) + } + + public registerDomain(name: string, commands: any) { + if (this.domains.has(name)) { + throw Error("Domain " + name + " is already registered") + } + + this.domains.set(name, commands) } public call(domain: string, command: string, ...params: any[]): Promise { return new Promise((resolve: (value: T) => void, reject: (error?: any) => void) => { - var id = this.messageIdCounter++; + const id = this.messageIdCounter++ this.callbacks.set(id, new PromiseCallback(resolve, reject)) this.transport.send(id, domain, command, params) }) } - messageReceived(message: Array) { - if (message.length === 1 || (message.length === 2 && !(typeof message[1] === 'string'))) { - var promiseCallback = this.callbacks.get(message[0]) - var singletonArray = safeGet(message, 1) + private messageReceived(message: Array) { + if (message.length === 1 || (message.length === 2 && !(typeof message[1] === "string"))) { + const promiseCallback = this.callbacks.get(message[0]) + const singletonArray = safeGet(message, 1) if (singletonArray == null) { promiseCallback.resolve() } @@ -45,9 +81,9 @@ export class JsonRpc { } } else { - var id: number - var offset: number - if (typeof message[0] === 'string') { + let id: number + let offset: number + if (typeof message[0] === "string") { id = -1 offset = 0 } @@ -56,21 +92,31 @@ export class JsonRpc { offset = 1 } - var onRejected = id === -1 ? null : (error: any) => this.transport.sendError(id, error) + const domainName = message[offset] + if (domainName === "e") { + console.assert(id != -1) + console.assert(message.length === 3) + this.callbacks.get(id).reject(message[2]) + return + } + + const onRejected = id === -1 ? null : (error: any) => this.transport.sendError(id, error) try { - var object = this.domains.get(message[offset]) - var method = object[message[offset + 1]] - var result: any - var args = safeGet(message, offset + 2) - if (args === null) { - result = method.call(object) - } - else { - result = method.apply(object, args) + const object = this.domains.get(domainName) + if (object == null) { + const e = "Cannot find domain " + domainName + console.warn(e) + if (onRejected != null) { + onRejected(e) + } + return } + const method = object[message[offset + 1]] + const args = safeGet(message, offset + 2) + const result: any = (args === null) ? method.call(object) : method.apply(object, args) if (id !== -1) { - var onFulfilled = (result: any) => this.transport.sendResult(id, result) + const onFulfilled = (result: any) => this.transport.sendResult(id, result) if (result instanceof Promise) { (>result).done(onFulfilled, onRejected) } diff --git a/platform/built-in-server/client/node-rpc-client/test/test.js b/platform/built-in-server/client/node-rpc-client/test/test.js index 5fa4efa3f6cc..712c2b3fd70a 100644 --- a/platform/built-in-server/client/node-rpc-client/test/test.js +++ b/platform/built-in-server/client/node-rpc-client/test/test.js @@ -1,30 +1,19 @@ -const should = require("should") -const rpcClient = require("../out/rpc-client") +const assertThat = require("should/as-function") + +const rpcNode = require("../out/rpc-node") const rpc = require("../out/rpc") describe("RPC", function () { it("connect", function (done) { - const transport = new rpcClient.SocketTransport() + const transport = new rpcNode.SocketTransport() transport.opened = function () { done() } transport.connect() }) - it("connect", function (done) { - this.timeout(5000000) - const transport = new rpcClient.SocketTransport() - transport.opened = function () { - } - transport.connect(63343) - - const rpcServer = new rpc.JsonRpc(transport) - rpcServer.call("Ide", "about") - .then(function (r) { - console.log(r) - done() - }, function (e) { - throw e - }) + it("call method", function () { + const rpcServer = rpcNode.connect(63343) + return assertThat(rpcServer.call("Ide", "about")).fulfilled() }) }) \ No newline at end of file diff --git a/platform/built-in-server/client/node-rpc-client/tsconfig.json b/platform/built-in-server/client/node-rpc-client/tsconfig.json index c7a0c1aa243f..09f524694bbe 100644 --- a/platform/built-in-server/client/node-rpc-client/tsconfig.json +++ b/platform/built-in-server/client/node-rpc-client/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "module": "commonjs", - "target": "es6", + "target": "es5", "noImplicitAny": true, "removeComments": true, "outDir": "out", @@ -18,7 +18,7 @@ "files": [ "typings/bluebird/bluebird.d.ts", "typings/node/node.d.ts", - "src/rpc-client.ts", + "src/rpc-node.ts", "src/rpc.ts" ] } diff --git a/platform/built-in-server/client/node-rpc-client/tsd.json b/platform/built-in-server/client/node-rpc-client/tsd.json index 924203dfa87c..fb9bc081f931 100644 --- a/platform/built-in-server/client/node-rpc-client/tsd.json +++ b/platform/built-in-server/client/node-rpc-client/tsd.json @@ -9,6 +9,9 @@ }, "bluebird/bluebird.d.ts": { "commit": "dc9dabe74a5be62613b17a3605309783a12ff28a" + }, + "debug/debug.d.ts": { + "commit": "627b6c158b73494c803f36fc2fe00ad75faa8fde" } } } diff --git a/platform/built-in-server/client/node-rpc-client/typings/debug/debug.d.ts b/platform/built-in-server/client/node-rpc-client/typings/debug/debug.d.ts new file mode 100644 index 000000000000..b43cd238c3cf --- /dev/null +++ b/platform/built-in-server/client/node-rpc-client/typings/debug/debug.d.ts @@ -0,0 +1,38 @@ +// Type definitions for debug +// Project: https://github.com/visionmedia/debug +// Definitions by: Seon-Wook Park , Gal Talmor +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare var debug: debug.IDebug; + +// Support AMD require +declare module 'debug' { + export = debug; +} + +declare module debug { + export interface IDebug { + (namespace: string): debug.IDebugger, + coerce: (val: any) => any, + disable: () => void, + enable: (namespaces: string) => void, + enabled: (namespaces: string) => boolean, + + names: string[], + skips: string[], + + formatters: IFormatters + } + + export interface IFormatters { + [formatter: string]: Function + } + + export interface IDebugger { + (formatter: any, ...args: any[]): void; + + enabled: boolean; + log: Function; + namespace: string; + } +} diff --git a/platform/built-in-server/src/net.kt b/platform/built-in-server/src/net.kt new file mode 100644 index 000000000000..64cbc78e096c --- /dev/null +++ b/platform/built-in-server/src/net.kt @@ -0,0 +1,7 @@ +package com.intellij.util.net + +import java.net.InetAddress +import java.net.InetSocketAddress + +@JvmOverloads +fun loopbackSocketAddress(port: Int = -1) = InetSocketAddress(InetAddress.getLoopbackAddress(), if (port == -1) NetUtils.findAvailableSocketPort() else port) \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt b/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt index 1b30103e9440..1e498e716b19 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.kt @@ -3,7 +3,7 @@ package org.jetbrains.builtInWebServer import com.intellij.execution.process.OSProcessHandler import com.intellij.openapi.project.Project import com.intellij.util.Consumer -import com.intellij.util.net.NetUtils +import com.intellij.util.net.loopbackSocketAddress import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel import org.jetbrains.concurrency.AsyncPromise @@ -11,7 +11,6 @@ import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.catchError import org.jetbrains.concurrency.resolvedPromise import org.jetbrains.io.* -import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicReference abstract class SingleConnectionNetService(project: Project) : NetService(project) { @@ -29,7 +28,7 @@ abstract class SingleConnectionNetService(project: Project) : NetService(project this.bootstrap = bootstrap this.port = port - bootstrap.connect(InetSocketAddress(NetUtils.getLoopbackAddress(), port), promise)?.let { + bootstrap.connect(loopbackSocketAddress(port), promise)?.let { promise.catchError { processChannel.set(it) addCloseListener(it) @@ -45,7 +44,7 @@ abstract class SingleConnectionNetService(project: Project) : NetService(project } val promise = AsyncPromise() - bootstrap!!.connect(InetSocketAddress(NetUtils.getLoopbackAddress(), port), promise)?.let { + bootstrap!!.connect(loopbackSocketAddress(port), promise)?.let { promise.catchError { processChannel.set(it) addCloseListener(it) diff --git a/platform/built-in-server/src/org/jetbrains/io/SubServer.java b/platform/built-in-server/src/org/jetbrains/io/SubServer.java index 96f4f13693ad..c5e58d805f36 100644 --- a/platform/built-in-server/src/org/jetbrains/io/SubServer.java +++ b/platform/built-in-server/src/org/jetbrains/io/SubServer.java @@ -19,7 +19,7 @@ import com.intellij.ide.XmlRpcServer; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Disposer; -import com.intellij.util.net.NetUtils; +import com.intellij.util.net.NetKt; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; @@ -76,7 +76,7 @@ public final class SubServer implements CustomPortServerManager.CustomPortServic } try { - bootstrap.localAddress(user.isAvailableExternally() ? new InetSocketAddress(port) : new InetSocketAddress(NetUtils.getLoopbackAddress(), port)); + bootstrap.localAddress(user.isAvailableExternally() ? new InetSocketAddress(port) : NetKt.loopbackSocketAddress(port)); channelRegistrar.add(bootstrap.bind().syncUninterruptibly().channel()); return true; } diff --git a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt index 7d79cdbbf4f3..08e57eb93001 100644 --- a/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt +++ b/platform/built-in-server/src/org/jetbrains/io/fastCgi/FastCgiService.kt @@ -26,6 +26,7 @@ import io.netty.channel.Channel import io.netty.handler.codec.http.* import org.jetbrains.builtInWebServer.SingleConnectionNetService import org.jetbrains.concurrency.Promise +import org.jetbrains.concurrency.doneRun import org.jetbrains.io.* import java.util.concurrent.atomic.AtomicInteger @@ -82,8 +83,8 @@ abstract class FastCgiService(project: Project) : SingleConnectionNetService(pro promise = processHandler.get() } - (promise as Promise) - .done { fastCgiRequest.writeToServerChannel(notEmptyContent, processChannel.get()!!) } + promise + .doneRun { fastCgiRequest.writeToServerChannel(notEmptyContent, processChannel.get()!!) } .rejected { Promise.logError(LOG, it) handleError(fastCgiRequest, notEmptyContent) diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/Client.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/Client.java index 9480877340eb..e53cb5a09808 100644 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/Client.java +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/Client.java @@ -34,6 +34,7 @@ public abstract class Client extends UserDataHolderBase { return channel.alloc(); } + @NotNull protected abstract ChannelFuture send(@NotNull ByteBuf message); public abstract void sendHeartbeat(); diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.java deleted file mode 100644 index 891ba6b9fed7..000000000000 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.jetbrains.io.jsonRpc; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.SimpleTimer; -import com.intellij.openapi.util.SimpleTimerTask; -import gnu.trove.THashSet; -import gnu.trove.TObjectProcedure; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.AttributeKey; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.concurrency.AsyncPromise; -import org.jetbrains.io.webSocket.WebSocketServerOptions; - -import java.util.List; - -public class ClientManager implements Disposable { - public static final AttributeKey CLIENT = AttributeKey.valueOf("SocketHandler.client"); - - private final SimpleTimerTask heartbeatTimer; - - @Nullable - private final ClientListener listener; - - @NotNull - public final ExceptionHandler exceptionHandler; - - private final THashSet clients = new THashSet(); - - public ClientManager() { - this(null, new ExceptionHandlerImpl()); - } - - public ClientManager(@Nullable ClientListener listener, @NotNull ExceptionHandler exceptionHandler) { - this(null, exceptionHandler, listener); - } - - public ClientManager(@Nullable WebSocketServerOptions options, @NotNull ExceptionHandler exceptionHandler, @Nullable ClientListener listener) { - this.exceptionHandler = exceptionHandler; - this.listener = listener; - - heartbeatTimer = SimpleTimer.getInstance().setUp(new Runnable() { - @Override - public void run() { - synchronized (clients) { - if (clients.isEmpty()) { - return; - } - - clients.forEach(new TObjectProcedure() { - @Override - public boolean execute(Client client) { - if (client.channel.isActive()) { - client.sendHeartbeat(); - } - return true; - } - }); - } - } - }, (options == null ? new WebSocketServerOptions() : options).heartbeatDelay); - } - - public void addClient(@NotNull Client client) { - synchronized (clients) { - clients.add(client); - } - } - - public int getClientCount() { - synchronized (clients) { - return clients.size(); - } - } - - public boolean hasClients() { - return getClientCount() > 0; - } - - @Override - public void dispose() { - try { - heartbeatTimer.cancel(); - } - finally { - synchronized (clients) { - clients.clear(); - } - } - } - - public void send(final int messageId, @NotNull final ByteBuf message, @Nullable final List>> results) { - forEachClient(new TObjectProcedure() { - private boolean first; - - @Override - public boolean execute(final Client client) { - try { - AsyncPromise> result = client.send(messageId, first ? message : message.duplicate()); - first = false; - if (results != null) { - results.add(result); - } - } - catch (Throwable e) { - exceptionHandler.exceptionCaught(e); - } - return true; - } - }); - } - - public boolean disconnectClient(@NotNull ChannelHandlerContext context, @NotNull Client client, boolean closeChannel) { - synchronized (clients) { - if (!clients.remove(client)) { - return false; - } - } - - try { - context.attr(CLIENT).remove(); - - if (closeChannel) { - context.channel().close(); - } - - client.rejectAsyncResults(exceptionHandler); - } - finally { - if (listener != null) { - listener.disconnected(client); - } - } - return true; - } - - public void forEachClient(@NotNull TObjectProcedure procedure) { - synchronized (clients) { - if (clients.isEmpty()) { - return; - } - - clients.forEach(procedure); - } - } -} \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.kt b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.kt new file mode 100644 index 000000000000..5bed61f85081 --- /dev/null +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/ClientManager.kt @@ -0,0 +1,104 @@ +package org.jetbrains.io.jsonRpc + +import com.intellij.openapi.Disposable +import com.intellij.openapi.util.SimpleTimer +import gnu.trove.THashSet +import gnu.trove.TObjectProcedure +import io.netty.buffer.ByteBuf +import io.netty.channel.ChannelHandlerContext +import io.netty.util.AttributeKey +import org.jetbrains.concurrency.Promise +import org.jetbrains.io.webSocket.WebSocketServerOptions + +val CLIENT = AttributeKey.valueOf("SocketHandler.client") + +class ClientManager(private val listener: ClientListener?, val exceptionHandler: ExceptionHandler, options: WebSocketServerOptions? = null) : Disposable { + private val heartbeatTimer = SimpleTimer.getInstance().setUp(Runnable { + synchronized (clients) { + if (clients.isEmpty) { + return@Runnable + } + + clients.forEach { client -> + if (client.channel.isActive) { + client.sendHeartbeat() + } + true + } + } + }, (options ?: WebSocketServerOptions()).heartbeatDelay.toLong()) + + private val clients = THashSet() + + fun addClient(client: Client) { + synchronized (clients) { + clients.add(client) + } + } + + val clientCount: Int + get() = synchronized (clients) { clients.size } + + fun hasClients() = clientCount > 0 + + override fun dispose() { + try { + heartbeatTimer.cancel() + } + finally { + synchronized (clients) { + clients.clear() + } + } + } + + fun send(messageId: Int, message: ByteBuf, results: MutableList>>? = null) { + forEachClient(object : TObjectProcedure { + private var first: Boolean = false + + override fun execute(client: Client): Boolean { + try { + val result = client.send>(messageId, if (first) message else message.duplicate()) + first = false + results?.add(result!!) + } + catch (e: Throwable) { + exceptionHandler.exceptionCaught(e) + } + return true + } + }) + } + + fun disconnectClient(context: ChannelHandlerContext, client: Client, closeChannel: Boolean): Boolean { + synchronized (clients) { + if (!clients.remove(client)) { + return false + } + } + + try { + context.attr(CLIENT).remove() + + if (closeChannel) { + context.channel().close() + } + + client.rejectAsyncResults(exceptionHandler) + } + finally { + listener?.disconnected(client) + } + return true + } + + fun forEachClient(procedure: TObjectProcedure) { + synchronized (clients) { + if (clients.isEmpty) { + return + } + + clients.forEach(procedure) + } + } +} \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.java deleted file mode 100644 index 857b711f0ce5..000000000000 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.java +++ /dev/null @@ -1,411 +0,0 @@ -package org.jetbrains.io.jsonRpc; - -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.util.ArrayUtil; -import com.intellij.util.ArrayUtilRt; -import com.intellij.util.Consumer; -import com.intellij.util.SmartList; -import com.intellij.util.text.CharSequenceBackedByArray; -import gnu.trove.THashMap; -import gnu.trove.TIntArrayList; -import gnu.trove.TIntProcedure; -import io.netty.buffer.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.concurrency.AsyncPromise; -import org.jetbrains.concurrency.Promise; -import org.jetbrains.io.JsonReaderEx; -import org.jetbrains.io.JsonUtil; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -public class JsonRpcServer implements MessageServer { - protected static final Logger LOG = Logger.getInstance(JsonRpcServer.class); - - private static final TypeAdapterFactory INT_LIST_TYPE_ADAPTER_FACTORY = new TypeAdapterFactory() { - private IntArrayListTypeAdapter typeAdapter; - - @Nullable - @Override - public TypeAdapter create(Gson gson, TypeToken type) { - if (type.getType() != TIntArrayList.class) { - return null; - } - if (typeAdapter == null) { - typeAdapter = new IntArrayListTypeAdapter(); - } - //noinspection unchecked - return (TypeAdapter)typeAdapter; - } - }; - - private final AtomicInteger messageIdCounter = new AtomicInteger(); - private final ClientManager clientManager; - private final Gson gson; - - private final Map domains = new THashMap(); - - public JsonRpcServer(@NotNull ClientManager clientManager) { - this.clientManager = clientManager; - gson = new GsonBuilder().registerTypeAdapter(CharSequenceBackedByArray.class, new JsonSerializer() { - @Override - public JsonElement serialize(CharSequenceBackedByArray src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.toString()); - } - }).registerTypeAdapterFactory(INT_LIST_TYPE_ADAPTER_FACTORY).disableHtmlEscaping().create(); - } - - public void registerDomain(@NotNull String name, @NotNull NotNullLazyValue commands) { - registerDomain(name, commands, false); - } - - public void registerDomain(@NotNull String name, @NotNull NotNullLazyValue commands, boolean overridable) { - if (domains.containsKey(name)) { - if (overridable) { - return; - } - else { - throw new IllegalArgumentException(name + " is already registered"); - } - } - - domains.put(name, commands); - } - - @Override - public void messageReceived(@NotNull Client client, @NotNull CharSequence message, boolean isBinary) throws IOException { - if (LOG.isDebugEnabled()) { - LOG.debug("IN " + message); - } - - JsonReaderEx reader = new JsonReaderEx(message); - if (!isBinary) { - reader.beginArray(); - } - else { - // to allow top-level member to be not a object or array - reader.setLenient(true); - } - - int messageId = reader.peek() == JsonToken.NUMBER ? reader.nextInt() : -1; - String domainName = reader.nextString(); - if (domainName.length() == 1) { - AsyncPromise promise = client.messageCallbackMap.remove(messageId); - if (domainName.charAt(0) == 'r') { - if (promise == null) { - LOG.error("Response with id " + messageId + " was already processed"); - return; - } - promise.setResult(JsonUtil.nextAny(reader)); - } - else { - promise.setError("error"); - } - return; - } - - NotNullLazyValue domainHolder = domains.get(domainName); - if (domainHolder == null) { - LOG.error("Cannot find domain " + domainName); - return; - } - - Object domain = domainHolder.getValue(); - String command = reader.nextString(); - if (domain instanceof JsonServiceInvocator) { - ((JsonServiceInvocator)domain).invoke(command, client, reader, messageId, message); - return; - } - - Object[] parameters; - if (reader.hasNext()) { - List list = new SmartList(); - JsonUtil.readListBody(reader, list); - parameters = ArrayUtil.toObjectArray(list); - } - else { - parameters = ArrayUtilRt.EMPTY_OBJECT_ARRAY; - } - - if (!isBinary) { - reader.endArray(); - } - - try { - boolean isStatic = domain instanceof Class; - Method[] methods; - if (isStatic) { - methods = ((Class)domain).getDeclaredMethods(); - } - else { - methods = domain.getClass().getMethods(); - } - for (Method method : methods) { - if (method.getName().equals(command)) { - method.setAccessible(true); - Object result = method.invoke(isStatic ? null : domain, parameters); - if (messageId != -1) { - if (result instanceof ByteBuf) { - ByteBuf buffer = (ByteBuf)result; - boolean success = false; - try { - client.send(encodeMessage(client.getByteBufAllocator(), messageId, null, null, buffer, null)); - success = true; - } - finally { - if (!success) { - buffer.release(); - } - } - } - else { - client.send(encodeMessage(client.getByteBufAllocator(), messageId, null, null, null, new Object[]{result})); - } - } - return; - } - } - - throw new NoSuchMethodException(command); - } - catch (Throwable e) { - throw new IOException(e); - } - } - - public void sendResponse(int messageId, @NotNull Client client, @Nullable ByteBuf rawMessage) { - client.send(encodeMessage(client.getByteBufAllocator(), messageId, null, null, rawMessage, ArrayUtil.EMPTY_OBJECT_ARRAY)); - } - - public void sendErrorResponse(int messageId, @NotNull Client client, @Nullable CharSequence rawMessage) { - client.send(encodeMessage(client.getByteBufAllocator(), messageId, "e", null, null, new Object[]{rawMessage})); - } - - public void sendToClients(@NotNull String domain, @NotNull String command, @Nullable List>> results, Object... params) { - if (clientManager.hasClients()) { - sendToClients(results == null ? -1 : messageIdCounter.getAndIncrement(), domain, command, results, params); - } - } - - private void sendToClients(int messageId, @Nullable String domain, @Nullable String command, @Nullable List>> results, Object[] params) { - clientManager.send(messageId, encodeMessage(ByteBufAllocator.DEFAULT, messageId, domain, command, null, params), results); - } - - public boolean sendWithRawPart(@NotNull Client client, @NotNull String domain, @NotNull String command, @Nullable ByteBuf rawMessage, Object... params) { - client.send(encodeMessage(client.getByteBufAllocator(), -1, domain, command, rawMessage, params)); - return true; - } - - public void send(@NotNull Client client, @NotNull String domain, @NotNull String command, Object... params) { - sendWithRawPart(client, domain, command, null, params); - } - - @NotNull - public Promise call(@NotNull Client client, @NotNull String domain, @NotNull String command, Object... params) { - int messageId = messageIdCounter.getAndIncrement(); - ByteBuf message = encodeMessage(client.getByteBufAllocator(), messageId, domain, command, null, params); - AsyncPromise result = client.send(messageId, message); - LOG.assertTrue(result != null); - return result; - } - - @NotNull - private ByteBuf encodeMessage(@NotNull ByteBufAllocator byteBufAllocator, - int messageId, - @Nullable String domain, - @Nullable String command, - @Nullable ByteBuf rawData, - @Nullable Object[] params) { - ByteBuf buffer = byteBufAllocator.ioBuffer(); - boolean success = false; - try { - Object[] notNullParams = params == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : params; - buffer = doEncodeMessage(byteBufAllocator, buffer, messageId, domain, command, notNullParams, rawData); - if (LOG.isDebugEnabled()) { - LOG.debug("OUT " + domain + '.' + command + (notNullParams.length == 0 ? "" : " " + Arrays.toString(params)) + (rawData == null ? "" : " " + rawData.toString(CharsetToolkit.UTF8_CHARSET))); - } - success = true; - return buffer; - } - catch (IOException e) { - throw new RuntimeException(e); - } - finally { - if (!success) { - buffer.release(); - } - } - } - - @NotNull - private ByteBuf doEncodeMessage(@NotNull ByteBufAllocator byteBufAllocator, - @NotNull ByteBuf buffer, - int id, - @Nullable String domain, - @Nullable String command, - @NotNull Object[] params, - @Nullable ByteBuf rawData) throws IOException { - buffer.writeByte('['); - ByteBuf effectiveBuffer = buffer; - boolean hasPrev = false; - StringBuilder sb = null; - if (id != -1) { - sb = new StringBuilder(); - ByteBufUtil.writeAscii(buffer, sb.append(id)); - sb.setLength(0); - hasPrev = true; - } - - if (domain != null) { - if (hasPrev) { - buffer.writeByte(','); - } - buffer.writeByte('"'); - ByteBufUtil.writeAscii(buffer, domain); - buffer.writeByte('"').writeByte(',').writeByte('"'); - if (command == null) { - if (rawData != null) { - effectiveBuffer = byteBufAllocator.compositeBuffer().addComponent(buffer).addComponent(rawData); - buffer = byteBufAllocator.ioBuffer(); - } - buffer.writeByte('"'); - return addBuffer(effectiveBuffer, buffer); - } - else { - ByteBufUtil.writeAscii(buffer, command); - buffer.writeByte('"'); - } - } - - encodeParameters(buffer, params, sb); - if (rawData != null) { - if (params.length > 0) { - buffer.writeByte(','); - } - effectiveBuffer = byteBufAllocator.compositeBuffer().addComponent(buffer).addComponent(rawData); - buffer = byteBufAllocator.ioBuffer(); - } - buffer.writeByte(']'); - - buffer.writeByte(']'); - return addBuffer(effectiveBuffer, buffer); - } - - @NotNull - // addComponent always add sliced component, so, we must add last buffer only after all writes - private static ByteBuf addBuffer(@NotNull ByteBuf buffer, @NotNull ByteBuf lastComponent) { - if (buffer != lastComponent) { - ((CompositeByteBuf)buffer).addComponent(lastComponent); - buffer.writerIndex(buffer.capacity()); - } - return buffer; - } - - private void encodeParameters(@NotNull ByteBuf buffer, @NotNull Object[] params, @Nullable StringBuilder sb) throws IOException { - JsonWriter writer = null; - buffer.writeByte(',').writeByte('['); - boolean hasPrev = false; - for (Object param : params) { - if (hasPrev) { - buffer.writeByte(','); - } - else { - hasPrev = true; - } - - // gson - SOE if param has type class com.intellij.openapi.editor.impl.DocumentImpl$MyCharArray, so, use hack - if (param instanceof CharSequence) { - JsonUtil.escape(((CharSequence)param), buffer); - } - else if (param == null) { - ByteBufUtil.writeAscii(buffer, "null"); - } - else if (param instanceof Boolean) { - ByteBufUtil.writeAscii(buffer, param.toString()); - } - else if (param instanceof Number) { - if (sb == null) { - sb = new StringBuilder(); - } - if (param instanceof Integer) { - sb.append(((Integer)param).intValue()); - } - else if (param instanceof Long) { - sb.append(((Long)param).longValue()); - } - else if (param instanceof Float) { - sb.append(((Float)param).floatValue()); - } - else if (param instanceof Double) { - sb.append(((Double)param).doubleValue()); - } - else { - sb.append(param.toString()); - } - ByteBufUtil.writeAscii(buffer, sb); - sb.setLength(0); - } - else if (param instanceof Consumer) { - if (sb == null) { - sb = new StringBuilder(); - } - //noinspection unchecked - ((Consumer)param).consume(sb); - ByteBufUtilEx.writeUtf8(buffer, sb); - sb.setLength(0); - } - else { - if (writer == null) { - writer = new JsonWriter(new ByteBufUtf8Writer(buffer)); - } - //noinspection unchecked - ((TypeAdapter)gson.getAdapter(param.getClass())).write(writer, param); - } - } - } - - private static class IntArrayListTypeAdapter extends TypeAdapter { - @Override - public void write(final JsonWriter out, T value) throws IOException { - final Ref error = new Ref(); - out.beginArray(); - ((TIntArrayList)value).forEach(new TIntProcedure() { - @Override - public boolean execute(int value) { - try { - out.value(value); - } - catch (IOException e) { - error.set(e); - } - return error.isNull(); - } - }); - - if (!error.isNull()) { - throw error.get(); - } - - out.endArray(); - } - - @Override - public T read(com.google.gson.stream.JsonReader in) throws IOException { - throw new UnsupportedOperationException(); - } - } -} diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt new file mode 100644 index 000000000000..d7d73f985a54 --- /dev/null +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/JsonRpcServer.kt @@ -0,0 +1,353 @@ +package org.jetbrains.io.jsonRpc + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonToken +import com.google.gson.stream.JsonWriter +import com.intellij.openapi.Disposable +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.NotNullLazyValue +import com.intellij.util.ArrayUtil +import com.intellij.util.ArrayUtilRt +import com.intellij.util.Consumer +import com.intellij.util.SmartList +import gnu.trove.THashMap +import gnu.trove.TIntArrayList +import io.netty.buffer.* +import org.jetbrains.concurrency.Promise +import org.jetbrains.io.JsonReaderEx +import org.jetbrains.io.JsonUtil +import org.jetbrains.io.releaseIfError +import java.io.IOException +import java.lang.reflect.Method +import java.util.concurrent.atomic.AtomicInteger + +private val LOG = Logger.getInstance(JsonRpcServer::class.java) + +private val INT_LIST_TYPE_ADAPTER_FACTORY = object : TypeAdapterFactory { + private var typeAdapter: IntArrayListTypeAdapter? = null + + override fun create(gson: Gson, type: TypeToken): TypeAdapter? { + if (type.type !== TIntArrayList::class.java) { + return null + } + + if (typeAdapter == null) { + typeAdapter = IntArrayListTypeAdapter() + } + @Suppress("CAST_NEVER_SUCCEEDS") + return typeAdapter as TypeAdapter? + } +} + +private val gson by lazy { + GsonBuilder() + .registerTypeAdapterFactory(INT_LIST_TYPE_ADAPTER_FACTORY) + .disableHtmlEscaping() + .create() +} + +class JsonRpcServer(private val clientManager: ClientManager) : MessageServer { + private val messageIdCounter = AtomicInteger() + private val domains = THashMap>() + + fun registerDomain(name: String, commands: NotNullLazyValue<*>, overridable: Boolean = false, disposable: Disposable? = null) { + if (domains.containsKey(name)) { + if (overridable) { + return + } + else { + throw IllegalArgumentException("$name is already registered") + } + } + + domains.put(name, commands) + if (disposable != null) { + Disposer.register(disposable, Disposable { domains.remove(name) }) + } + } + + override fun messageReceived(client: Client, message: CharSequence) { + if (LOG.isDebugEnabled) { + LOG.debug("IN $message") + } + + val reader = JsonReaderEx(message) + reader.beginArray() + + val messageId = if (reader.peek() == JsonToken.NUMBER) reader.nextInt() else -1 + val domainName = reader.nextString() + if (domainName.length == 1) { + val promise = client.messageCallbackMap.remove(messageId) + if (domainName[0] == 'r') { + if (promise == null) { + LOG.error("Response with id $messageId was already processed") + return + } + promise.setResult(JsonUtil.nextAny(reader)) + } + else { + promise!!.setError("error") + } + return + } + + val domainHolder = domains[domainName] + if (domainHolder == null) { + processClientError(client, "Cannot find domain $domainName", messageId) + return + } + + val domain = domainHolder.value + val command = reader.nextString() + if (domain is JsonServiceInvocator) { + domain.invoke(command, client, reader, messageId, message) + return + } + + val parameters: Array + if (reader.hasNext()) { + val list = SmartList() + JsonUtil.readListBody(reader, list) + parameters = ArrayUtil.toObjectArray(list) + } + else { + parameters = ArrayUtilRt.EMPTY_OBJECT_ARRAY + } + + val isStatic = domain is Class<*> + val methods: Array + if (isStatic) { + methods = (domain as Class<*>).declaredMethods + } + else { + methods = domain.javaClass.methods + } + for (method in methods) { + if (method.name == command) { + method.isAccessible = true + val result = method.invoke(if (isStatic) null else domain, *parameters) + if (messageId != -1) { + if (result is ByteBuf) { + result.releaseIfError { + client.send(encodeMessage(client.byteBufAllocator, messageId, rawData = result)) + } + } + else { + client.send(encodeMessage(client.byteBufAllocator, messageId, params = arrayOf(result))) + } + } + return + } + } + + processClientError(client, "Cannot find method $domain.$command", messageId) + } + + private fun processClientError(client: Client, error: String, messageId: Int) { + try { + LOG.error(error) + } + finally { + if (messageId != -1) { + sendErrorResponse(client, messageId, error) + } + } + } + + fun sendResponse(client: Client, messageId: Int, rawData: ByteBuf? = null) { + client.send(encodeMessage(client.byteBufAllocator, messageId, rawData = rawData)) + } + + fun sendErrorResponse(client: Client, messageId: Int, message: CharSequence?) { + client.send(encodeMessage(client.byteBufAllocator, messageId, "e", params = arrayOf(message))) + } + + fun sendWithRawPart(client: Client, domain: String, command: String, rawData: ByteBuf, params: Array<*>): Boolean { + return client.send(encodeMessage(client.byteBufAllocator, -1, domain, command, rawData = rawData, params = params)).cause() == null + } + + fun send(client: Client, domain: String, command: String, vararg params: Any?) { + client.send(encodeMessage(client.byteBufAllocator, -1, domain, command, params = params)) + } + + fun call(client: Client, domain: String, command: String, vararg params: Any?): Promise { + val messageId = messageIdCounter.andIncrement + val message = encodeMessage(client.byteBufAllocator, messageId, domain, command, params = params) + return client.send(messageId, message)!! + } + + fun send(domain: String, command: String, vararg params: Any?) { + if (clientManager.hasClients()) { + val messageId = -1 + val message = encodeMessage(ByteBufAllocator.DEFAULT, messageId, domain, command, params = params) + clientManager.send(messageId, message) + } + } + + private fun encodeMessage(byteBufAllocator: ByteBufAllocator, + messageId: Int = -1, + domain: String? = null, + command: String? = null, + rawData: ByteBuf? = null, + params: Array<*> = ArrayUtil.EMPTY_OBJECT_ARRAY): ByteBuf { + val buffer = doEncodeMessage(byteBufAllocator, messageId, domain, command, params, rawData) + if (LOG.isDebugEnabled) { + LOG.debug("OUT ${buffer.toString(Charsets.UTF_8)}") + } + return buffer + } + + private fun doEncodeMessage(byteBufAllocator: ByteBufAllocator, + id: Int, + domain: String?, + command: String?, + params: Array<*>, + rawData: ByteBuf?): ByteBuf { + var buffer = byteBufAllocator.ioBuffer() + buffer.writeByte('[') + var sb: StringBuilder? = null + if (id != -1) { + sb = StringBuilder() + buffer.writeAscii(sb.append(id)) + sb.setLength(0) + } + + if (domain != null) { + if (id != -1) { + buffer.writeByte(',') + } + buffer.writeByte('"').writeAscii(domain).writeByte('"') + if (command != null) { + buffer.writeByte(',').writeByte('"').writeAscii(command).writeByte('"') + } + } + + var effectiveBuffer = buffer + if (params.isNotEmpty() || rawData != null) { + buffer.writeByte(',').writeByte('[') + encodeParameters(buffer, params, sb) + if (rawData != null) { + if (params.isNotEmpty()) { + buffer.writeByte(',') + } + effectiveBuffer = byteBufAllocator.compositeBuffer().addComponent(buffer).addComponent(rawData) + buffer = byteBufAllocator.ioBuffer() + } + buffer.writeByte(']') + } + + buffer.writeByte(']') + return effectiveBuffer.addBuffer(buffer) + } + + private fun encodeParameters(buffer: ByteBuf, params: Array<*>, _sb: StringBuilder?) { + var sb = _sb + var writer: JsonWriter? = null + var hasPrev = false + for (param in params) { + if (hasPrev) { + buffer.writeByte(',') + } + else { + hasPrev = true + } + + // gson - SOE if param has type class com.intellij.openapi.editor.impl.DocumentImpl$MyCharArray, so, use hack + if (param is CharSequence) { + JsonUtil.escape(param, buffer) + } + else if (param == null) { + buffer.writeAscii("null") + } + else if (param is Boolean) { + buffer.writeAscii(param.toString()) + } + else if (param is Number) { + if (sb == null) { + sb = StringBuilder() + } + if (param is Int) { + sb.append(param.toInt()) + } + else if (param is Long) { + sb.append(param.toLong()) + } + else if (param is Float) { + sb.append(param.toFloat()) + } + else if (param is Double) { + sb.append(param.toDouble()) + } + else { + sb.append(param.toString()) + } + buffer.writeAscii(sb) + sb.setLength(0) + } + else if (param is Consumer<*>) { + if (sb == null) { + sb = StringBuilder() + } + @Suppress("UNCHECKED_CAST") + (param as Consumer).consume(sb) + ByteBufUtilEx.writeUtf8(buffer, sb) + sb.setLength(0) + } + else { + if (writer == null) { + writer = JsonWriter(ByteBufUtf8Writer(buffer)) + } + (gson.getAdapter(param.javaClass) as TypeAdapter).write(writer, param) + } + } + } +} + +private fun ByteBuf.writeByte(c: Char) = writeByte(c.toInt()) + +private fun ByteBuf.writeAscii(s: CharSequence): ByteBuf { + ByteBufUtil.writeAscii(this, s) + return this +} + +private class IntArrayListTypeAdapter : TypeAdapter() { + override fun write(out: JsonWriter, value: T) { + var error: IOException? = null + out.beginArray() + (value as TIntArrayList).forEach { value -> + try { + out.value(value.toLong()) + } + catch (e: IOException) { + error = e + } + + error == null + } + + error?.let { throw it } + out.endArray() + } + + override fun read(`in`: com.google.gson.stream.JsonReader) = throw UnsupportedOperationException() +} + +// addComponent always add sliced component, so, we must add last buffer only after all writes +private fun ByteBuf.addBuffer(buffer: ByteBuf): ByteBuf { + if (this !== buffer) { + (this as CompositeByteBuf).addComponent(buffer) + writerIndex(capacity()) + } + return this +} + +fun JsonRpcServer.registerFromEp() { + for (domainBean in JsonRpcDomainBean.EP_NAME.extensions) { + registerDomain(domainBean.name, domainBean.value, domainBean.overridable) + } +} \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/MessageServer.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/MessageServer.java index c80d7d78d551..7770530acbb5 100644 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/MessageServer.java +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/MessageServer.java @@ -2,8 +2,6 @@ package org.jetbrains.io.jsonRpc; import org.jetbrains.annotations.NotNull; -import java.io.IOException; - public interface MessageServer { - void messageReceived(@NotNull Client client, @NotNull CharSequence message, boolean isBinary) throws IOException; + void messageReceived(@NotNull Client client, @NotNull CharSequence message); } \ No newline at end of file diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/RpcBinaryRequestHandler.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/RpcBinaryRequestHandler.java index 3f59d4c259e6..8f0b44c7cfcd 100644 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/RpcBinaryRequestHandler.java +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/RpcBinaryRequestHandler.java @@ -9,6 +9,7 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.ide.BinaryRequestHandler; import org.jetbrains.ide.BuiltInServerManager; import org.jetbrains.io.MessageDecoder; @@ -18,7 +19,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; -class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionHandler, ClientListener { +public class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionHandler, ClientListener { private static final Logger LOG = Logger.getInstance(RpcBinaryRequestHandler.class); private static final UUID ID = UUID.fromString("69957EEB-AFB8-4036-A9A8-00D2D022F9BD"); @@ -27,18 +28,26 @@ class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionH @NotNull @Override protected ClientManager compute() { - ClientManager result = new ClientManager(RpcBinaryRequestHandler.this, RpcBinaryRequestHandler.this); + ClientManager result = new ClientManager(RpcBinaryRequestHandler.this, RpcBinaryRequestHandler.this, null); Disposable serverDisposable = BuiltInServerManager.getInstance().getServerDisposable(); assert serverDisposable != null; Disposer.register(serverDisposable, result); rpcServer = new JsonRpcServer(result); + JsonRpcServerKt.registerFromEp(rpcServer); return result; } }; private JsonRpcServer rpcServer; + @NotNull + @TestOnly + public JsonRpcServer getRpcServer() { + clientManager.getValue(); + return rpcServer; + } + @NotNull @Override public UUID getId() { @@ -49,7 +58,7 @@ class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionH @Override public ChannelHandler getInboundHandler(@NotNull ChannelHandlerContext context) { SocketClient client = new SocketClient(context.channel()); - context.attr(ClientManager.CLIENT).set(client); + context.attr(ClientManagerKt.getCLIENT()).set(client); clientManager.getValue().addClient(client); connected(client, null); return new MyDecoder(client); @@ -102,10 +111,10 @@ class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionH } try { - rpcServer.messageReceived(client, content, true); + rpcServer.messageReceived(client, content); } catch (Throwable e) { - clientManager.getValue().exceptionHandler.exceptionCaught(e); + clientManager.getValue().getExceptionHandler().exceptionCaught(e); } finally { contentLength = 0; @@ -118,7 +127,7 @@ class RpcBinaryRequestHandler extends BinaryRequestHandler implements ExceptionH @Override public void channelInactive(ChannelHandlerContext context) throws Exception { - Client client = context.attr(ClientManager.CLIENT).get(); + Client client = context.attr(ClientManagerKt.getCLIENT()).get(); // if null, so, has already been explicitly removed if (client != null) { clientManager.getValue().disconnectClient(context, client, false); diff --git a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/SocketClient.java b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/SocketClient.java index b9c6252fc2cb..44e9de3b12e1 100644 --- a/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/SocketClient.java +++ b/platform/built-in-server/src/org/jetbrains/io/jsonRpc/socket/SocketClient.java @@ -13,10 +13,11 @@ public class SocketClient extends Client { super(channel); } + @NotNull @Override public ChannelFuture send(@NotNull ByteBuf message) { if (channel.isOpen()) { - ByteBuf lengthBuffer = channel.alloc().buffer(4); + ByteBuf lengthBuffer = channel.alloc().ioBuffer(4); lengthBuffer.writeInt(message.readableBytes()); channel.write(lengthBuffer); return channel.writeAndFlush(message); diff --git a/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java b/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java index effa1f5b53b2..1cb37b07287a 100644 --- a/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java +++ b/platform/built-in-server/src/org/jetbrains/io/webSocket/MessageChannelHandler.java @@ -8,6 +8,7 @@ import org.jetbrains.io.ChannelBufferToString; import org.jetbrains.io.SimpleChannelInboundHandlerAdapter; import org.jetbrains.io.jsonRpc.Client; import org.jetbrains.io.jsonRpc.ClientManager; +import org.jetbrains.io.jsonRpc.ClientManagerKt; import org.jetbrains.io.jsonRpc.MessageServer; @ChannelHandler.Sharable @@ -22,7 +23,7 @@ final class MessageChannelHandler extends SimpleChannelInboundHandlerAdapter { - override fun consume(error: Throwable) { - TestCase.fail(error.message) - } - }) + result.rejected { error -> TestCase.fail(error.message) } if (result.state == Promise.State.PENDING) { val semaphore = Semaphore() diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java index 2918656a952b..67d20c03359d 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/util/SegmentArray.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -92,6 +92,10 @@ public class SegmentArray { throw new IndexOutOfBoundsException("Wrong offset: " + offset + ". Should be in range: [0, " + lastValidOffset + "]"); } + /** + * @throws IllegalStateException if a gap between segments is detected, or if there are no segments and an index for a positive offset is + * requested + */ public final int findSegmentIndex(int offset) { if (mySegmentCount <= 0) { return offset == 0 ? 0 : noSegmentsAvailable(offset); @@ -126,7 +130,9 @@ public class SegmentArray { protected int segmentNotFound(int offset, int start) { // This means that there is a gap at given offset - assert myStarts[start] <= offset && offset < myEnds[start] : start; + if (offset < myStarts[start] || offset >= myEnds[start]) { + throw new IllegalStateException("Gap at offset " + offset + " near segment " + start); + } return start; } diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java index 7b05e682dcb6..2638143eee46 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/ZipHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,7 +21,6 @@ import com.intellij.openapi.util.io.FileAttributes; import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.io.FileAccessorCache; import com.intellij.util.text.ByteArrayCharSequence; import org.jetbrains.annotations.NotNull; @@ -217,8 +216,7 @@ public class ZipHandler extends ArchiveHandler { if (entry != null) { InputStream stream = zip.getInputStream(entry); if (stream != null) { - // ZipFile.c#Java_java_util_zip_ZipFile_read reads data in 8K (stack allocated) blocks - // no sense to create BufferedInputStream + // ZipFile.c#Java_java_util_zip_ZipFile_read reads data in 8K (stack allocated) blocks - no sense to create BufferedInputStream try { return FileUtil.loadBytes(stream, (int)entry.getSize()); } @@ -232,11 +230,11 @@ public class ZipHandler extends ArchiveHandler { zipRef.release(); } - return ArrayUtil.EMPTY_BYTE_ARRAY; + throw new FileNotFoundException(getFile() + "!/" + relativePath); } // also used in Kotlin public static void clearFileAccessorCache() { ourZipFileFileAccessorCache.clear(); } -} +} \ No newline at end of file diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java index 8d156ced6cbb..348f168d54bb 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java @@ -414,11 +414,21 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc return attrs; } + @Override + public String toString() { + return getClass().getName() + "(" + myLexer.getClass().getName() + ")"; + } + public class HighlighterIteratorImpl implements HighlighterIterator { private int mySegmentIndex = 0; HighlighterIteratorImpl(int startOffset) { - mySegmentIndex = mySegments.findSegmentIndex(startOffset); + try { + mySegmentIndex = mySegments.findSegmentIndex(startOffset); + } + catch (IllegalStateException e) { + throw new IllegalStateException("Wrong state of " + LexerEditorHighlighter.this, e); + } } public int currentIndex() { diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 225ce16d259a..c095258d7a20 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -249,37 +249,39 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { throw new AssertionError("You must not run search from within updating PSI activity. Please consider invokeLatering it instead."); } progress.pushState(); - progress.setText(PsiBundle.message("psi.scanning.files.progress")); + boolean result; + try { + progress.setText(PsiBundle.message("psi.scanning.files.progress")); - String text = searcher.getPattern(); - Set fileSet = new THashSet(); - getFilesWithText(scope, searchContext, caseSensitively, text, progress, fileSet); + String text = searcher.getPattern(); + Set fileSet = new THashSet(); + getFilesWithText(scope, searchContext, caseSensitively, text, progress, fileSet); - progress.setText(PsiBundle.message("psi.search.for.word.progress", text)); + progress.setText(PsiBundle.message("psi.search.for.word.progress", text)); - final Processor localProcessor = localProcessor(processor, progress, processInjectedPsi, searcher); - if (containerName != null) { - List intersectionWithContainerFiles = new ArrayList(); - // intersectionWithContainerFiles holds files containing words from both `text` and `containerName` - getFilesWithText(scope, searchContext, caseSensitively, text+" "+containerName, progress, intersectionWithContainerFiles); - if (!intersectionWithContainerFiles.isEmpty()) { - int totalSize = fileSet.size(); - boolean result = processPsiFileRoots(intersectionWithContainerFiles, totalSize, 0, progress, - localProcessor); + final Processor localProcessor = localProcessor(processor, progress, processInjectedPsi, searcher); + if (containerName != null) { + List intersectionWithContainerFiles = new ArrayList(); + // intersectionWithContainerFiles holds files containing words from both `text` and `containerName` + getFilesWithText(scope, searchContext, caseSensitively, text+" "+containerName, progress, intersectionWithContainerFiles); + if (!intersectionWithContainerFiles.isEmpty()) { + int totalSize = fileSet.size(); + result = processPsiFileRoots(intersectionWithContainerFiles, totalSize, 0, progress, localProcessor); - if (result) { - fileSet.removeAll(intersectionWithContainerFiles); - if (!fileSet.isEmpty()) { - result = processPsiFileRoots(new ArrayList(fileSet), totalSize, intersectionWithContainerFiles.size(), progress, localProcessor); + if (result) { + fileSet.removeAll(intersectionWithContainerFiles); + if (!fileSet.isEmpty()) { + result = processPsiFileRoots(new ArrayList(fileSet), totalSize, intersectionWithContainerFiles.size(), progress, localProcessor); + } } + return result; } - progress.popState(); - return result; } + result = fileSet.isEmpty() || processPsiFileRoots(new ArrayList(fileSet), fileSet.size(), 0, progress, localProcessor); + } + finally { + progress.popState(); } - - boolean result = fileSet.isEmpty() || processPsiFileRoots(new ArrayList(fileSet), fileSet.size(), 0, progress, localProcessor); - progress.popState(); return result; } @@ -485,52 +487,55 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { final int patternLength = searcher.getPattern().length(); progress.pushState(); - progress.setText(PsiBundle.message("psi.search.in.non.java.files.progress")); + final Ref cancelled = Ref.create(Boolean.FALSE); + try { + progress.setText(PsiBundle.message("psi.search.in.non.java.files.progress")); - final SearchScope useScope = originalElement == null ? null : ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SearchScope compute() { - return getUseScope(originalElement); - } - }); - - final Ref cancelled = new Ref(Boolean.FALSE); - for (int i = 0; i < files.length; i++) { - progress.checkCanceled(); - final PsiFile psiFile = files[i]; - if (psiFile instanceof PsiBinaryFile) continue; - - final CharSequence text = ApplicationManager.getApplication().runReadAction(new Computable() { + final SearchScope useScope = originalElement == null ? null : ApplicationManager.getApplication().runReadAction(new Computable() { @Override - public CharSequence compute() { - return psiFile.getViewProvider().getContents(); + public SearchScope compute() { + return getUseScope(originalElement); } }); - LowLevelSearchUtil.processTextOccurrences(text, 0, text.length(), searcher, progress, new TIntProcedure() { - @Override - public boolean execute(final int index) { - boolean isReferenceOK = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Boolean compute() { - PsiReference referenceAt = psiFile.findReferenceAt(index); - return referenceAt == null || useScope == null || - !PsiSearchScopeUtil.isInScope(useScope.intersectWith(initialScope), psiFile); - } - }); - if (isReferenceOK && !processor.process(psiFile, index, index + patternLength)) { - cancelled.set(Boolean.TRUE); - return false; + for (int i = 0; i < files.length; i++) { + progress.checkCanceled(); + final PsiFile psiFile = files[i]; + if (psiFile instanceof PsiBinaryFile) continue; + + final CharSequence text = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public CharSequence compute() { + return psiFile.getViewProvider().getContents(); } + }); - return true; - } - }); - if (cancelled.get()) break; - progress.setFraction((double)(i + 1) / files.length); + LowLevelSearchUtil.processTextOccurrences(text, 0, text.length(), searcher, progress, new TIntProcedure() { + @Override + public boolean execute(final int index) { + boolean isReferenceOK = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Boolean compute() { + PsiReference referenceAt = psiFile.findReferenceAt(index); + return referenceAt == null || useScope == null || !PsiSearchScopeUtil.isInScope(useScope.intersectWith(initialScope), psiFile); + } + }); + if (isReferenceOK && !processor.process(psiFile, index, index + patternLength)) { + cancelled.set(Boolean.TRUE); + return false; + } + + return true; + } + }); + if (cancelled.get()) break; + progress.setFraction((double)(i + 1) / files.length); + } + } + finally { + progress.popState(); } - progress.popState(); return !cancelled.get(); } diff --git a/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java b/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java index 8424662d824f..7c0b4296d52a 100644 --- a/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java +++ b/platform/lang-api/src/com/intellij/execution/util/EnvVariablesTable.java @@ -30,6 +30,7 @@ import com.intellij.util.ui.ListTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.table.TableCellEditor; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.util.ArrayList; @@ -93,6 +94,14 @@ public class EnvVariablesTable extends ListTableWithButtons protected String getDescription(EnvironmentVariable environmentVariable) { return environmentVariable.getDescription(); } + + @Nullable + @Override + public TableCellEditor getEditor(EnvironmentVariable variable) { + StringWithNewLinesCellEditor editor = new StringWithNewLinesCellEditor(); + editor.setClickCountToStart(1); + return editor; + } }; return new ListTableModel((new ColumnInfo[]{name, value})); diff --git a/platform/lang-api/src/com/intellij/execution/util/StringWithNewLinesCellEditor.java b/platform/lang-api/src/com/intellij/execution/util/StringWithNewLinesCellEditor.java new file mode 100644 index 000000000000..5fbc94ac5a4b --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/util/StringWithNewLinesCellEditor.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2016 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.execution.util; + +import com.intellij.ui.components.JBTextField; + +import javax.swing.*; +import javax.swing.text.Document; + +public class StringWithNewLinesCellEditor extends DefaultCellEditor { + + public StringWithNewLinesCellEditor() { + super(new JBTextField() { + @Override + public void setDocument(Document doc) { + super.setDocument(doc); + doc.putProperty("filterNewlines", Boolean.FALSE); + } + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/animation/ArrangementAnimationManager.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/animation/ArrangementAnimationManager.java index 3bf858cb0603..73b5af2f1d2c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/animation/ArrangementAnimationManager.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/animation/ArrangementAnimationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,6 +16,7 @@ package com.intellij.application.options.codeStyle.arrangement.animation; import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -28,7 +29,7 @@ import java.awt.event.ActionListener; */ public class ArrangementAnimationManager implements ArrangementAnimationPanel.Listener, ActionListener { - @NotNull private final Timer myTimer = new Timer(ArrangementConstants.ANIMATION_STEPS_TIME_GAP_MILLIS, this); + @NotNull private final Timer myTimer = UIUtil.createNamedTimer("ArrangementAnimation", ArrangementConstants.ANIMATION_STEPS_TIME_GAP_MILLIS, this); @NotNull private final ArrangementAnimationPanel myAnimationPanel; @NotNull private final Callback myCallback; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java index d3d159f2df39..3d55ed673c03 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/UpdateFoldRegionsOperation.java @@ -248,7 +248,7 @@ class UpdateFoldRegionsOperation implements Runnable { } private boolean regionCanBeRemovedWhenCollapsed(FoldRegion region) { - return Boolean.TRUE.equals(region.getUserData(CAN_BE_REMOVED_WHEN_COLLAPSED)) || isRegionInCaretLine(region); + return Boolean.TRUE.equals(region.getUserData(CAN_BE_REMOVED_WHEN_COLLAPSED)) || !region.isValid() || isRegionInCaretLine(region); } private boolean isRegionInCaretLine(FoldRegion region) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java index 69ee66e83a12..30bb4b94af18 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java @@ -252,6 +252,11 @@ public final class NavigationUtil { @NotNull public static JBPopup getRelatedItemsPopup(final List items, String title) { + return getRelatedItemsPopup(items, title, false); + } + + @NotNull + public static JBPopup getRelatedItemsPopup(final List items, String title, boolean requiresModuleShowing) { Object[] elements = new Object[items.size()]; //todo[nik] move presentation logic to GotoRelatedItem class final Map itemsMap = new HashMap(); @@ -261,7 +266,7 @@ public final class NavigationUtil { itemsMap.put(item.getElement(), item); } - return getPsiElementPopup(elements, itemsMap, title, new Processor() { + return getPsiElementPopup(elements, itemsMap, title, requiresModuleShowing, new Processor() { @Override public boolean process(Object element) { if (element instanceof PsiElement) { @@ -278,7 +283,7 @@ public final class NavigationUtil { } private static JBPopup getPsiElementPopup(final Object[] elements, final Map itemsMap, - final String title, final Processor processor) { + final String title, final boolean requiresModuleShowing, final Processor processor) { final Ref hasMnemonic = Ref.create(false); final DefaultPsiElementCellRenderer renderer = new DefaultPsiElementCellRenderer() { @@ -313,7 +318,7 @@ public final class NavigationUtil { @Override protected DefaultListCellRenderer getRightCellRenderer(Object value) { - return null; + return requiresModuleShowing ? super.getRightCellRenderer(value) : null; } @Override diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ShowRunningListAction.java b/platform/lang-impl/src/com/intellij/execution/actions/ShowRunningListAction.java index fe2a542ac763..2e0d7b10ba3d 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ShowRunningListAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ShowRunningListAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -37,6 +37,7 @@ import com.intellij.ui.LayeredIcon; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -60,7 +61,7 @@ public class ShowRunningListAction extends AnAction { final Ref> stateRef = new Ref>(); final Ref balloonRef = new Ref(); - final Timer timer = new Timer(250, null); + final Timer timer = UIUtil.createNamedTimer("runningLists", 250); ActionListener actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { diff --git a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java index 896c34cebb9e..616d2942537d 100644 --- a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -72,10 +72,12 @@ public class RunLineMarkerProvider extends LineMarkerProviderDescriptor { final StringBuilder tooltip = new StringBuilder(); for (RunLineMarkerContributor.Info info : infos) { if (info.tooltipProvider != null) { + String string = info.tooltipProvider.fun(element); + if (string == null) continue; if (tooltip.length() != 0) { tooltip.append("\n"); } - tooltip.append(info.tooltipProvider.fun(element)); + tooltip.append(string); } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/JBPopupMenu.java b/platform/platform-api/src/com/intellij/openapi/ui/JBPopupMenu.java index d394397aa108..51b3531b34ef 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/JBPopupMenu.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/JBPopupMenu.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,6 +20,7 @@ import com.intellij.ui.ColorUtil; import com.intellij.ui.JBColor; import com.intellij.ui.ScreenUtil; import com.intellij.util.ui.GraphicsUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -90,7 +91,7 @@ public class JBPopupMenu extends JPopupMenu { public MyLayout(final JPopupMenu target) { super(target, BoxLayout.PAGE_AXIS); myTarget = target; - myTimer = new Timer(40, this); + myTimer = UIUtil.createNamedTimer("PopupTimer", 40, this); myTarget.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { diff --git a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java index 9f800030ad86..0fc901464382 100644 --- a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java +++ b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -18,6 +18,7 @@ package com.intellij.ui; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,7 +40,7 @@ public class JBCardLayout extends CardLayout { private Map myMap = new LinkedHashMap(); private int mySwipeTime = 200;//default value, provide setter if need private int mySwipeSteps = 20;//default value, provide setter if need - private final Timer myTimer = new Timer(Math.max(1, mySwipeTime / mySwipeSteps), null); + private final Timer myTimer = UIUtil.createNamedTimer("CardLayoutTimer",Math.max(1, mySwipeTime / mySwipeSteps)); private Component mySwipeFrom = null; private Component mySwipeTo = null; diff --git a/platform/platform-api/src/com/intellij/ui/components/AbstractScrollBarUI.java b/platform/platform-api/src/com/intellij/ui/components/AbstractScrollBarUI.java index 10ce0f93ccf9..97ba2f587332 100644 --- a/platform/platform-api/src/com/intellij/ui/components/AbstractScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/ui/components/AbstractScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -17,18 +17,18 @@ package com.intellij.ui.components; import com.intellij.openapi.util.Key; import com.intellij.ui.JBColor; -import com.intellij.ui.components.JBScrollBar.Alignment; +import com.intellij.ui.components.JBScrollPane.Alignment; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.RegionPainter; import com.intellij.util.ui.UIUtil; -import java.awt.*; -import java.awt.event.*; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.ScrollBarUI; +import java.awt.*; +import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -44,7 +44,7 @@ abstract class AbstractScrollBarUI extends ScrollBarUI { private static final JBColor TRACK_FOREGROUND = new JBColor(0xE6E6E6, 0x3C3F41); private final Listener myListener = new Listener(); - private final Timer myScrollTimer = new Timer(60, myListener); + private final Timer myScrollTimer = UIUtil.createNamedTimer("ScrollBarUITimer",60, myListener); private final Rectangle myThumbBounds = new Rectangle(); private final Rectangle myTrackBounds = new Rectangle(); diff --git a/platform/platform-api/src/com/intellij/ui/components/DefaultScrollBarUI.java b/platform/platform-api/src/com/intellij/ui/components/DefaultScrollBarUI.java index 029c3b707d84..112bdaa5bb97 100644 --- a/platform/platform-api/src/com/intellij/ui/components/DefaultScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/ui/components/DefaultScrollBarUI.java @@ -17,7 +17,7 @@ package com.intellij.ui.components; import com.intellij.ui.Gray; import com.intellij.ui.JBColor; -import com.intellij.ui.components.JBScrollBar.Alignment; +import com.intellij.ui.components.JBScrollPane.Alignment; import java.awt.AlphaComposite; import java.awt.Composite; diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollBar.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollBar.java index 4473f0afcec0..268010e9e70f 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollBar.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollBar.java @@ -52,30 +52,4 @@ public class JBScrollBar extends JScrollBar { public void updateUI() { setUI(ButtonlessScrollBarUI.createNormal()); } - - /** - * Positions of a ScrollBar on a ScrollPane. - */ - enum Alignment { - TOP, LEFT, RIGHT, BOTTOM; - - static Alignment get(JComponent component) { - if (component instanceof JScrollBar) { - Object property = component.getClientProperty(Alignment.class); - if (property instanceof Alignment) return (Alignment)property; - - if (component.getParent() instanceof JScrollPane) { - switch (((JScrollBar)component).getOrientation()) { - case Adjustable.HORIZONTAL: - return BOTTOM; - case Adjustable.VERTICAL: - return component.getParent().getComponentOrientation().isLeftToRight() - ? RIGHT - : LEFT; - } - } - } - return null; - } - } } diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index e9a4b1bd4861..c3155ad40f2c 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -19,7 +19,6 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeGlassPane; import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.components.JBScrollBar.Alignment; import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionUtil; import com.intellij.util.ui.ButtonlessScrollBarUI; @@ -359,6 +358,40 @@ public class JBScrollPane extends JScrollPane { NONE, VERTICAL, HORIZONTAL, BOTH } + /** + * These client properties show a component position on a scroll pane. + * It is set by internal layout manager of the scroll pane. + */ + enum Alignment { + TOP, LEFT, RIGHT, BOTTOM; + + static Alignment get(JComponent component) { + if (component != null) { + Object property = component.getClientProperty(Alignment.class); + if (property instanceof Alignment) return (Alignment)property; + + Container parent = component.getParent(); + if (parent instanceof JScrollPane) { + JScrollPane pane = (JScrollPane)parent; + if (component == pane.getColumnHeader()) { + return TOP; + } + if (component == pane.getHorizontalScrollBar()) { + return BOTTOM; + } + boolean ltr = pane.getComponentOrientation().isLeftToRight(); + if (component == pane.getVerticalScrollBar()) { + return ltr ? RIGHT : LEFT; + } + if (component == pane.getRowHeader()) { + return ltr ? LEFT : RIGHT; + } + } + } + return null; + } + } + /** * ScrollPaneLayout implementation that supports * ScrollBar flipping and non-opaque ScrollBars. diff --git a/platform/platform-api/src/com/intellij/util/Alarm.java b/platform/platform-api/src/com/intellij/util/Alarm.java index 30a5fafc1ad2..beab3a7ed346 100644 --- a/platform/platform-api/src/com/intellij/util/Alarm.java +++ b/platform/platform-api/src/com/intellij/util/Alarm.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -408,7 +408,9 @@ public class Alarm implements Disposable { future.cancel(false); assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; // TODO Use java.util.concurrent.ScheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true) when on jdk 1.7 - ((ThreadPoolExecutor)JobScheduler.getScheduler()).remove((Runnable)future); + if (JobScheduler.getScheduler() instanceof ThreadPoolExecutor) { + ((ThreadPoolExecutor)JobScheduler.getScheduler()).remove((Runnable)future); + } myFuture = null; } Runnable task = myTask; diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java index c742c386f124..df3f2870a199 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -100,7 +100,7 @@ public class ITNReporter extends ErrorReportSubmitter { final PluginId pluginId = IdeErrorsDialog.findPluginId(t); if (pluginId != null) { final IdeaPluginDescriptor ideaPluginDescriptor = PluginManager.getPlugin(pluginId); - if (ideaPluginDescriptor != null && !ideaPluginDescriptor.isBundled()) { + if (ideaPluginDescriptor != null && (!ideaPluginDescriptor.isBundled() || ideaPluginDescriptor.allowBundledUpdate())) { errorBean.setPluginName(ideaPluginDescriptor.getName()); errorBean.setPluginVersion(ideaPluginDescriptor.getVersion()); } diff --git a/platform/platform-impl/src/com/intellij/execution/process/ProcessUtils.java b/platform/platform-impl/src/com/intellij/execution/process/ProcessUtils.java new file mode 100644 index 000000000000..d01b84f2bc8c --- /dev/null +++ b/platform/platform-impl/src/com/intellij/execution/process/ProcessUtils.java @@ -0,0 +1,232 @@ +/* + * Copyright 2000-2015 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. + */ + +/****************************************************************************** + * Copyright (C) 2013 Fabio Zadrozny + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Fabio Zadrozny - initial API and implementation + ******************************************************************************/ +package com.intellij.execution.process; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jvnet.winp.WinProcess; +import org.jvnet.winp.WinpException; + +import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ProcessUtils { + private static final Logger LOG = Logger.getInstance(ProcessUtils.class); + + /** + * Passes the commands directly to Runtime.exec (with the passed envp) + */ + @NotNull + public static Process createProcess(String[] cmdarray, String[] envp, File workingDir) throws IOException { + return Runtime.getRuntime().exec(getWithoutEmptyParams(cmdarray), getWithoutEmptyParams(envp), workingDir); + } + + /** + * @return a new array without any null/empty elements originally contained in the array. + */ + @Nullable + private static String[] getWithoutEmptyParams(@Nullable String[] cmdarray) { + if (cmdarray == null) { + return null; + } + ArrayList list = new ArrayList(); + for (String string : cmdarray) { + if (string != null && string.length() > 0) { + list.add(string); + } + } + return ArrayUtil.toStringArray(list); + } + + @NotNull + public static IProcessList getProcessList(@NotNull String helpersRoot) { + if (SystemInfo.isWindows) { + return new ProcessListWin32(helpersRoot); + } + if (SystemInfo.isLinux) { + return new ProcessListLinux(); + } + if (SystemInfo.isMac) { + return new ProcessListMac(); + } + + LOG.error("Unexpected platform. Unable to list processes."); + return new IProcessList() { + + @Override + public ProcessInfo[] getProcessList() { + return new ProcessInfo[0]; + } + }; + } + + @NotNull + public static char[] loadFileText(@NotNull File file, @Nullable String encoding) throws IOException { + InputStream stream = new FileInputStream(file); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + Reader reader = encoding == null ? new InputStreamReader(stream) : new InputStreamReader(stream, encoding); + try { + return loadText(reader); + } + finally { + reader.close(); + } + } + + @NotNull + public static char[] loadText(@NotNull Reader reader) throws IOException { + //fill a buffer with the contents + int BUFFER_SIZE = 2 * 1024; + + char[] readBuffer = new char[BUFFER_SIZE]; + int n = reader.read(readBuffer); + + int DEFAULT_FILE_SIZE = 8 * BUFFER_SIZE; + + StringBuilder builder = new StringBuilder(DEFAULT_FILE_SIZE); + + while (n > 0) { + builder.append(readBuffer, 0, n); + n = reader.read(readBuffer); + } + + return builder.toString().toCharArray(); + } + + public static boolean killProcessTree(@NotNull Process process) { + if (SystemInfo.isWindows) { + try { + WinProcess winProcess = createWinProcess(process); + winProcess.killRecursively(); + return true; + } + catch (Throwable e) { + LOG.info("Cannot kill process tree", e); + } + } + else if (SystemInfo.isUnix) { + return UnixProcessManager.sendSigKillToProcessTree(process); + } + return false; + } + + public static void killProcess(@NotNull Process process) { + if (SystemInfo.isWindows) { + try { + WinProcess winProcess = createWinProcess(process); + winProcess.kill(); + } + catch (Throwable e) { + LOG.info("Cannot kill process", e); + } + } + else if (SystemInfo.isUnix) { + UnixProcessManager.sendSignal(UnixProcessManager.getProcessPid(process), UnixProcessManager.SIGKILL); + } + } + + public static int getProcessID(@NotNull Process process) { + if (SystemInfo.isWindows) { + try { + return createWinProcess(process).getPid(); + } + catch (Throwable e) { + LOG.info("Cannot get process id", e); + return -1; + } + } + else if (SystemInfo.isUnix) { + return UnixProcessManager.getProcessPid(process); + } + throw new IllegalStateException("Unknown OS: " + SystemInfo.OS_NAME); + } + + @SuppressWarnings("deprecation") + @NotNull + private static WinProcess createWinProcess(@NotNull Process process) { + if (process instanceof RunnerWinProcess) process = ((RunnerWinProcess)process).getOriginalProcess(); + return new WinProcess(process); + } + + @Nullable + public static List getCommandLinesOfRunningProcesses() { + try { + if (SystemInfo.isWindows) { + List commandLines = new ArrayList(); + for (WinProcess process : WinProcess.all()) { + try { + commandLines.add(process.getCommandLine()); + } + catch (WinpException ignored) { } + } + return commandLines; + } + else { + String[] cmd = UnixProcessManager.getPSCmd(true); + Process process = Runtime.getRuntime().exec(cmd); + List outputLines = readLines(process.getInputStream(), false); + List errorLines = readLines(process.getErrorStream(), false); + if (!errorLines.isEmpty()) { + throw new IOException(Arrays.toString(cmd) + " failed: " + StringUtil.join(errorLines, "\n")); + } + + //trim 'ps' output header + return outputLines.subList(1, outputLines.size()); + } + } + catch (Throwable e) { + LOG.info("Cannot collect command lines"); + LOG.info(e); + return null; + } + } + + @NotNull + private static List readLines(@NotNull InputStream inputStream, boolean includeEmpty) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + try { + List lines = new ArrayList(); + String line; + while ((line = reader.readLine()) != null) { + if (includeEmpty || !line.isEmpty()) { + lines.add(line); + } + } + return lines; + } + finally { + reader.close(); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java b/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java index 80b32a154dfe..ae92de5cf003 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java @@ -16,91 +16,32 @@ package com.intellij.execution.process.impl; import com.intellij.execution.process.OSProcessManager; -import com.intellij.execution.process.ProcessInfo; -import com.intellij.execution.process.RunnerWinProcess; -import com.intellij.execution.process.UnixProcessManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.SystemInfo; +import com.intellij.execution.process.ProcessUtils; import org.jetbrains.annotations.NotNull; -import org.jvnet.winp.WinProcess; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** * @author nik */ public class OSProcessManagerImpl extends OSProcessManager { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.impl.OSProcessManagerImpl"); - - @NotNull - public static ProcessInfo[] getProcessList() { - return ProcessListUtil.getProcessList(); - } - @Override public boolean killProcessTree(@NotNull Process process) { - if (SystemInfo.isWindows) { - try { - WinProcess winProcess = createWinProcess(process); - winProcess.killRecursively(); - return true; - } - catch (Throwable e) { - LOG.info("Cannot kill process tree", e); - } - } - else if (SystemInfo.isUnix) { - return UnixProcessManager.sendSigKillToProcessTree(process); - } - return false; + return ProcessUtils.killProcessTree(process); } public static void killProcess(@NotNull Process process) { - if (SystemInfo.isWindows) { - try { - WinProcess winProcess = createWinProcess(process); - winProcess.kill(); - } - catch (Throwable e) { - LOG.info("Cannot kill process", e); - } - } - else if (SystemInfo.isUnix) { - UnixProcessManager.sendSignal(UnixProcessManager.getProcessPid(process), UnixProcessManager.SIGKILL); - } - } - - public static int getProcessID(@NotNull Process process) { - if (SystemInfo.isWindows) { - try { - return createWinProcess(process).getPid(); - } - catch (Throwable e) { - LOG.info("Cannot get process id", e); - return -1; - } - } - else if (SystemInfo.isUnix) { - return UnixProcessManager.getProcessPid(process); - } - throw new IllegalStateException("Unknown OS: " + SystemInfo.OS_NAME); + ProcessUtils.killProcess(process); } - @SuppressWarnings("deprecation") - @NotNull - private static WinProcess createWinProcess(@NotNull Process process) { - if (process instanceof RunnerWinProcess) process = ((RunnerWinProcess)process).getOriginalProcess(); - return new WinProcess(process); + public static int getProcessID(@NotNull Process process) { + return ProcessUtils.getProcessID(process); } @Override + @Nullable public List getCommandLinesOfRunningProcesses() { - List result = new ArrayList(); - for (ProcessInfo each : getProcessList()) { - result.add(each.getCommandLine()); - } - return Collections.unmodifiableList(result); + return ProcessUtils.getCommandLinesOfRunningProcesses(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java b/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java index 4a216b7557f6..8a2c8d6df278 100644 --- a/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java +++ b/platform/platform-impl/src/com/intellij/ide/ApplicationActivationStateManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -101,7 +101,7 @@ public class ApplicationActivationStateManager { state = State.DEACTIVATING; LOG.debug("The app is in the deactivating state"); - Timer timer = new Timer(Registry.intValue("application.deactivation.timeout"), new ActionListener() { + Timer timer = UIUtil.createNamedTimer("ApplicationDeactivation",Registry.intValue("application.deactivation.timeout"), new ActionListener() { public void actionPerformed(ActionEvent evt) { if (state.equals(State.DEACTIVATING)) { diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index 7eecee7d2ca2..16dbae57ef71 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -1156,7 +1156,7 @@ public class IdeEventQueue extends EventQueue { private final FrequentEventDetector myFrequentEventDetector = new FrequentEventDetector(1009, 100); @Override public void postEvent(@NotNull AWTEvent theEvent) { - myFrequentEventDetector.eventHappened(); + myFrequentEventDetector.eventHappened(theEvent); super.postEvent(theEvent); } diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java index 8fa1d4a212a2..5eb5d7087d4b 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -30,9 +30,10 @@ import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; -import com.intellij.util.ConcurrencyUtil; +import com.intellij.util.concurrency.BoundedTaskExecutor; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.ide.PooledThreadExecutor; import javax.swing.*; import javax.swing.border.CompoundBorder; @@ -42,19 +43,16 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardStep { private static final int COLS = 3; - private static final ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory( - "FeaturedPlugins", true, Thread.NORM_PRIORITY)); + private static final ExecutorService ourService = new BoundedTaskExecutor(PooledThreadExecutor.INSTANCE, 4); public final AtomicBoolean myCanceled = new AtomicBoolean(false); - private PluginGroups myPluginGroups; - private JLabel myInProgressLabel; + private final PluginGroups myPluginGroups; + private final JLabel myInProgressLabel; public CustomizeFeaturedPluginsStepPanel(PluginGroups pluginGroups) { setLayout(new GridLayout(1, 1)); @@ -89,9 +87,9 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt String title = entry.getKey(); String s = entry.getValue(); - int i = s.indexOf(":"); + int i = s.indexOf(':'); String topic = s.substring(0, i); - int j = s.indexOf(":", i + 1); + int j = s.indexOf(':', i + 1); final String description = s.substring(i + 1, j); final String pluginId = s.substring(j + 1); IdeaPluginDescriptor foundDescriptor = null; @@ -199,7 +197,7 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt @Override public void actionPerformed(ActionEvent e) { wrapperLayout.show(buttonWrapper, "progress"); - ourService.schedule(new Runnable() { + ourService.execute(new Runnable() { @Override public void run() { try { @@ -227,7 +225,7 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt } }); } - }, 0, TimeUnit.SECONDS); + }); } }); cancelLink.setListener(new LinkListener() { diff --git a/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java index d67323c95ded..f62211b496c9 100644 --- a/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -33,6 +33,7 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.openapi.wm.impl.FloatingDecorator; +import com.intellij.reference.SoftReference; import com.intellij.util.KeyedLazyInstanceEP; import com.intellij.util.containers.WeakValueHashMap; import gnu.trove.THashSet; @@ -42,9 +43,11 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -335,16 +338,15 @@ public class DataManagerImpl extends DataManager { // To prevent memory leak we have to wrap passed component into // the weak reference. For example, Swing often remembers menu items // that have DataContext as a field. - private final WeakReference myRef; - private WeakValueHashMap myUserData; - private final WeakValueHashMap myCachedData = new WeakValueHashMap(); + private final Reference myRef; + private Map myUserData; + private final Map myCachedData = new WeakValueHashMap(); public MyDataContext(final Component component) { myEventCount = -1; - myRef = new WeakReference(component); + myRef = component == null ? null : new WeakReference(component); } - public void setEventCount(int eventCount, Object caller) { assert caller instanceof IdeKeyEventDispatcher : "This method might be accessible from " + IdeKeyEventDispatcher.class.getName() + " only"; myCachedData.clear(); @@ -376,7 +378,7 @@ public class DataManagerImpl extends DataManager { @Nullable private Object doGetData(@NotNull String dataId) { - Component component = myRef.get(); + Component component = SoftReference.dereference(myRef); if (PlatformDataKeys.IS_MODAL_CONTEXT.is(dataId)) { if (component == null) { return null; @@ -398,7 +400,7 @@ public class DataManagerImpl extends DataManager { @NonNls public String toString() { - return "component=" + myRef.get(); + return "component=" + SoftReference.dereference(myRef); } @Override @@ -412,8 +414,9 @@ public class DataManagerImpl extends DataManager { getOrCreateMap().put(key, value); } - private WeakValueHashMap getOrCreateMap() { - WeakValueHashMap userData = myUserData; + @NotNull + private Map getOrCreateMap() { + Map userData = myUserData; if (userData == null) { myUserData = userData = new WeakValueHashMap(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/WeakTimerListener.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/WeakTimerListener.java index 74b1cb077b8b..4712ea97e591 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/WeakTimerListener.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/WeakTimerListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -15,10 +15,12 @@ */ package com.intellij.openapi.actionSystem.impl; -import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.TimerListener; +import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.application.ModalityState; +import org.jetbrains.annotations.NotNull; +import java.lang.ref.Reference; import java.lang.ref.WeakReference; /** @@ -26,13 +28,14 @@ import java.lang.ref.WeakReference; */ public class WeakTimerListener implements TimerListener { private final ActionManagerEx myManager; - private final WeakReference myRef; + private final Reference myRef; - public WeakTimerListener(ActionManagerEx manager, TimerListener delegate) { + public WeakTimerListener(@NotNull ActionManagerEx manager, @NotNull TimerListener delegate) { myManager = manager; myRef = new WeakReference(delegate); } + @Override public ModalityState getModalityState() { TimerListener delegate = myRef.get(); if (delegate != null) { @@ -44,6 +47,7 @@ public class WeakTimerListener implements TimerListener { } } + @Override public void run() { TimerListener delegate = myRef.get(); if (delegate != null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java index d61803d47835..0ead5ca41dcf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/LaterInvocator.java @@ -47,7 +47,7 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -@SuppressWarnings({"SSBasedInspection"}) +@SuppressWarnings("SSBasedInspection") public class LaterInvocator { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.impl.LaterInvocator"); private static final boolean DEBUG = LOG.isDebugEnabled(); @@ -83,7 +83,7 @@ public class LaterInvocator { private static final List ourModalEntities = ContainerUtil.createLockFreeCopyOnWriteList(); private static final List ourQueue = new ArrayList(); //protected by LOCK - private static volatile int ourQueueSkipCount = 0; // optimization + private static volatile int ourQueueSkipCount; // optimization private static final FlushQueue ourFlushQueueRunnable = new FlushQueue(); private static final Stack ourEventStack = new Stack(); // guarded by RUN_LOCK @@ -136,7 +136,7 @@ public class LaterInvocator { @NotNull static ActionCallback invokeLater(@NotNull Runnable runnable, @NotNull ModalityState modalityState, @NotNull Condition expired) { - ourFrequentEventDetector.eventHappened(); + ourFrequentEventDetector.eventHappened(runnable); final ActionCallback callback = new ActionCallback(); RunnableInfo runnableInfo = new RunnableInfo(runnable, modalityState, expired, callback); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index ec5e1f3eac15..0df463419333 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -1502,7 +1502,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } public int visualLineStartOffset(int visualLine) { - if (myUseNewRendering) return myView.visualLineStartOffset(visualLine); + if (myUseNewRendering) return myView.visualLineToOffset(visualLine); throw new UnsupportedOperationException(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java index 2dec93047231..0b635b21e7ab 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -116,7 +116,7 @@ public class FontInfo { String normalizedName = name.toLowerCase(Locale.getDefault()); return normalizedName.startsWith(normalizedFamilyName) && (normalizedName.endsWith(".otf") || normalizedName.endsWith(".ttf")) && - (style == -1 || style == ComplementaryFontsRegistry.getFontStyle(name)); + (style == -1 || style == getFontStyle(normalizedName)); } }; List files = new ArrayList(); @@ -143,6 +143,13 @@ public class FontInfo { return Collections.min(files, BY_NAME); } + private static int getFontStyle(@NotNull String fontFileNameLowercase) { + String baseName = fontFileNameLowercase.substring(0, fontFileNameLowercase.length() - 4); + if (baseName.endsWith("-it")) return Font.ITALIC; + else if (baseName.endsWith("-boldit")) return Font.BOLD | Font.ITALIC; + else return ComplementaryFontsRegistry.getFontStyle(fontFileNameLowercase); + } + private void parseProblemGlyphs() { myCheckedForProblemGlyphs = true; BufferedImage buffer = UIUtil.createImage(20, 20, BufferedImage.TYPE_INT_RGB); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java index 335e00aa3ccb..9bd75709003d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorCoordinateMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -189,6 +189,8 @@ class EditorCoordinateMapper { int visualLineToOffset(int visualLine) { int start = 0; int end = myDocument.getTextLength(); + if (visualLine <= 0) return start; + if (visualLine >= myView.getEditor().getVisibleLineCount()) return end; int current = 0; while (start <= end) { current = (start + end) / 2; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java index c54f04754089..f344935a9e18 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -175,12 +175,6 @@ public class EditorView implements TextDrawingCallback, Disposable, Dumpable { return myMapper.visualLineToOffset(visualLine); } - public int visualLineStartOffset(int visualLine) { - assertIsDispatchThread(); - myEditor.getSoftWrapModel().prepareToMapping(); - return myMapper.visualLineToOffset(visualLine); - } - @NotNull public VisualPosition xyToVisualPosition(@NotNull Point p) { assertIsDispatchThread(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextLayoutCache.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextLayoutCache.java index 47bc4e1aff3c..a1cfa0fa9ea6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextLayoutCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/TextLayoutCache.java @@ -16,6 +16,8 @@ package com.intellij.openapi.editor.impl.view; import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Attachment; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; @@ -35,6 +37,8 @@ import java.util.*; * @see LineLayout */ class TextLayoutCache implements PrioritizedDocumentListener, Disposable { + private static final Logger LOG = Logger.getInstance(TextLayoutCache.class); + private static final int MAX_CHUNKS_IN_ACTIVE_EDITOR = 1000; private static final int MAX_CHUNKS_IN_INACTIVE_EDITOR = 10; @@ -125,6 +129,7 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable { @NotNull LineLayout getLineLayout(int line) { checkDisposed(); + if (line >= myLines.size()) LOG.error("Unexpected cache state", new Attachment("editorState.txt", myView.getEditor().dumpState())); LineLayout result = myLines.get(line); if (result == null || result == myBidiNotRequiredMarker) { result = LineLayout.create(myView, line, result == myBidiNotRequiredMarker); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index e75258fe64f5..f464cdd44e90 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -85,7 +85,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent private static final Logger LOG = Logger.getInstance(FileTypeManagerImpl.class); // You must update all existing default configurations accordingly - private static final int VERSION = 16; + private static final int VERSION = 17; private static final ThreadLocal> FILE_TYPE_FIXED_TEMPORARILY = new ThreadLocal>(); // cached auto-detected file type. If the file was auto-detected as plain text or binary @@ -94,7 +94,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent private static final int DETECT_BUFFER_SIZE = 8192; // the number of bytes to read from the file to feed to the file type detector // must be sorted - private static final String DEFAULT_IGNORED = "*.hprof;*.pyc;*.pyo;*.rbc;*~;.DS_Store;.git;.hg;.svn;CVS;RCS;SCCS;__pycache__;_svn;rcs;vssver.scc;vssver2.scc;"; + private static final String DEFAULT_IGNORED = "*.hprof;*.pyc;*.pyo;*.rbc;*.yarb;*~;.DS_Store;.git;.hg;.svn;CVS;RCS;SCCS;__pycache__;_svn;rcs;vssver.scc;vssver2.scc;"; static { List strings = StringUtil.split(DEFAULT_IGNORED, ";"); for (int i = 0; i < strings.size(); i++) { @@ -1135,7 +1135,11 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent // we want .tox back to allow users selecting interpreters from it unignoreMask(".tox"); } - + + if (savedVersion < 17) { + addIgnore("*.rbc"); + } + myIgnoredFileCache.clearCache(); String counter = JDOMExternalizer.readString(state, "fileTypeChangedCounter"); diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index c876bb9694ec..f79e2dd5253d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -77,9 +77,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project private final boolean myLight; /** - * @param projectManager * @param filePath System-independent path - * @param projectName */ protected ProjectImpl(@NotNull ProjectManager projectManager, @NotNull String filePath, @@ -228,23 +226,13 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project @Override public VirtualFile getProjectFile() { - if (isDefault()) { - return null; - } - else { - return LocalFileSystem.getInstance().findFileByPath(getStateStore().getProjectFilePath()); - } + return isDefault() ? null : LocalFileSystem.getInstance().findFileByPath(getStateStore().getProjectFilePath()); } @Override public VirtualFile getBaseDir() { String path = isDefault() ? null : getStateStore().getProjectBasePath(); - if (path == null) { - return null; - } - else { - return LocalFileSystem.getInstance().findFileByPath(path); - } + return path == null ? null : LocalFileSystem.getInstance().findFileByPath(path); } @Nullable @@ -298,9 +286,13 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project if (progressIndicator != null) { progressIndicator.pushState(); } - super.init(progressIndicator); - if (progressIndicator != null) { - progressIndicator.popState(); + try { + init(progressIndicator); + } + finally { + if (progressIndicator != null) { + progressIndicator.popState(); + } } long time = System.currentTimeMillis() - start; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 166ec2a77db8..d7c27e57f614 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java @@ -227,11 +227,13 @@ public class JarHandler extends ZipHandler { reportIOErrorWithJars(original, mirror, e); return original; } - - if (progress != null) { - progress.popState(); + finally { + if (progress != null) { + progress.popState(); + } } + return mirror; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java index 3e93027c4675..b4e9f64e558f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java @@ -77,7 +77,7 @@ public class RefreshQueueImpl extends RefreshQueue implements Disposable { public void run() { try { myRefreshIndicator.start(); - AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Doing file refresh. " + session.toString()); + AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Doing file refresh. " + session); try { doScan(session); } @@ -96,7 +96,7 @@ public class RefreshQueueImpl extends RefreshQueue implements Disposable { } } }); - myEventCounter.eventHappened(); + myEventCounter.eventHappened(session); } private void doScan(RefreshSessionImpl session) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java index 004b665e2d56..8bd84b1c57cf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeMenuBar.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -103,7 +103,7 @@ public class IdeMenuBar extends JMenuBar implements IdeEventQueue.EventDispatche if (WindowManagerImpl.isFloatingMenuBarSupported()) { myAnimator = new MyAnimator(); - myActivationWatcher = new Timer(100, new MyActionListener()); + myActivationWatcher = UIUtil.createNamedTimer("IdeMenuBar",100, new MyActionListener()); myClockPanel = new ClockPanel(); myButton = new MyExitFullScreenButton(); add(myClockPanel); diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java index 22709298e887..df2ee2df4503 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsProducer.java @@ -16,7 +16,9 @@ package com.intellij.remote; import com.intellij.execution.ExecutionException; +import com.intellij.openapi.project.Project; import com.intellij.util.Consumer; +import org.jetbrains.annotations.Nullable; /** * @author traff @@ -31,10 +33,29 @@ public interface RemoteSdkCredentialsProducer { @Deprecated T getRemoteSdkCredentials() throws InterruptedException, ExecutionException; + /** + * Returns remote sdk credentials for instances saved on application level, + * e.g. only application level deployment configurations will be available. + * @return + * @throws InterruptedException + * @throws ExecutionException + * @deprecated + */ T getRemoteSdkCredentials(boolean allowSynchronousInteraction) throws InterruptedException, ExecutionException; + T getRemoteSdkCredentials(@Nullable Project project, boolean allowSynchronousInteraction) throws InterruptedException, ExecutionException; + + /** + * Produces remote sdk credentials for instances saved on application level, + * e.g. only application level deployment configurations will be available. + * @param allowSynchronousInteraction + * @param remoteSdkCredentialsConsumer + * @deprecated + */ void produceRemoteSdkCredentials(boolean allowSynchronousInteraction, Consumer remoteSdkCredentialsConsumer); + void produceRemoteSdkCredentials(@Nullable Project project, boolean allowSynchronousInteraction, Consumer remoteSdkCredentialsConsumer); + /** * @param remoteSdkCredentialsConsumer * @deprecated diff --git a/platform/platform-impl/src/com/intellij/ui/ColorPicker.java b/platform/platform-impl/src/com/intellij/ui/ColorPicker.java index 8bfd64da1541..0b642ae55c54 100644 --- a/platform/platform-impl/src/com/intellij/ui/ColorPicker.java +++ b/platform/platform-impl/src/com/intellij/ui/ColorPicker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -1065,7 +1065,7 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private DefaultColorPipette(@NotNull JComponent parent, @NotNull ColorListener colorListener) { super(parent, colorListener); - myTimer = new Timer(5, new ActionListener() { + myTimer = UIUtil.createNamedTimer("DefaultColorPipette",5, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updatePipette(); diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index 62cf1db7a322..eb9feb42982f 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -202,14 +202,13 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, protected void setTextToEditor(String text) { myEditor.getMarkupModel().removeAllHighlighters(); myEditor.getDocument().setText(text); + ((EditorImpl)myEditor).resetSizes(); myEditor.getHighlighter().setText(text); if (myTextAttributes != null) { myEditor.getMarkupModel().addRangeHighlighter(0, myEditor.getDocument().getTextLength(), HighlighterLayer.ADDITIONAL_SYNTAX, myTextAttributes, HighlighterTargetArea.EXACT_RANGE); } - ((EditorImpl)myEditor).resetSizes(); - ((EditorImpl)myEditor).setPaintSelection(mySelected); SelectionModel selectionModel = myEditor.getSelectionModel(); selectionModel.setSelection(0, mySelected ? myEditor.getDocument().getTextLength() : 0); diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 8281dc03f217..b491438ac5a8 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -214,7 +214,7 @@ public abstract class JBListTable { private static final int RESIZE_AMOUNT_PER_STEP = 5; private final TIntObjectHashMap myRowAnimationStates = new TIntObjectHashMap(); - private final Timer myAnimationTimer = new Timer(ANIMATION_STEP_MILLIS, this); + private final Timer myAnimationTimer = UIUtil.createNamedTimer("JBListTableTimer",ANIMATION_STEP_MILLIS, this); private final JTable myTable; public RowResizeAnimator(JTable table) { diff --git a/platform/platform-impl/src/org/jetbrains/concurrency/promise.kt b/platform/platform-impl/src/org/jetbrains/concurrency/promise.kt index 0548389aeb00..a198438ea378 100644 --- a/platform/platform-impl/src/org/jetbrains/concurrency/promise.kt +++ b/platform/platform-impl/src/org/jetbrains/concurrency/promise.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -45,6 +45,15 @@ inline fun Promise.done(node: Obsolescent, crossinline handler: (T) -> Un override fun consume(param: T) = handler(param) }) +@Suppress("UNCHECKED_CAST") +inline fun Promise<*>.doneRun(crossinline handler: () -> Unit) = (this as Promise).done { handler() } + +@Suppress("UNCHECKED_CAST") +inline fun Promise<*>.then(crossinline handler: () -> Unit): Promise<*> = (this as Promise).then { it: Any? -> handler() } + +@Suppress("UNCHECKED_CAST") +inline fun Promise<*>.processed(crossinline handler: () -> Unit): Promise<*> = (this as Promise).processed { it: Any? -> handler() } + inline fun Promise.thenAsync(node: Obsolescent, crossinline handler: (T) -> Promise) = thenAsync(object : ValueNodeAsyncFunction(node) { override fun `fun`(param: T) = handler(param) diff --git a/platform/platform-impl/src/org/jetbrains/io/netty.kt b/platform/platform-impl/src/org/jetbrains/io/netty.kt index c78d88bdf229..be2cf53a36f6 100644 --- a/platform/platform-impl/src/org/jetbrains/io/netty.kt +++ b/platform/platform-impl/src/org/jetbrains/io/netty.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,6 +19,7 @@ import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Conditions import io.netty.bootstrap.Bootstrap import io.netty.bootstrap.ServerBootstrap +import io.netty.buffer.ByteBuf import io.netty.channel.* import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.oio.OioEventLoopGroup @@ -58,7 +59,7 @@ fun oioClientBootstrap(): Bootstrap { } inline fun ChannelFuture.addListener(crossinline listener: (future: ChannelFuture) -> Unit) { - addListener(GenericFutureListener { future -> listener(future) }) + addListener(GenericFutureListener { listener(it) }) } // if NIO, so, it is shared and we must not shutdown it @@ -95,4 +96,18 @@ val Channel.uriScheme: String get() = if (pipeline().get(SslHandler::class.java) == null) "http" else "https" val HttpRequest.host: String - get() = headers().getAsString(HttpHeaderNames.HOST) \ No newline at end of file + get() = headers().getAsString(HttpHeaderNames.HOST) + +inline fun ByteBuf.releaseIfError(task: () -> T): T { + try { + return task() + } + catch (e: Exception) { + try { + release() + } + finally { + throw e + } + } +} \ No newline at end of file diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index 70481b725f2e..d2bb583f5661 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -36,4 +36,5 @@ ro.redeul.google.go 0.5.0 0.5.1 0.9.1 0.9.10 0.9.11 0.9.12 0.9.13 0.9.2 0.9.3 0. TFS 121.185 121.390 124.218 124.297 124.344 124.533 126.254 126.309 127.14 129.105 "Haxe Support" "0.9.7 for IDEA 14.1.4" com.sencha.idea.IdeaPlugin 6.0.6.456 6.0.4.438 6.0.3.430 6.0.2.414 6.0.1.396 6.0.0.390 "0.4.325 (SenchaCon 2015 EA)" "0.3.323 (SenchaCon 2015 EA)" "0.3.312 (SenchaCon 2015 EA)" "0.2.251 (SenchaCon 2015 EA)" "0.1.211 (SenchaCon 2015 EA)" "0.1.210.1 (SenchaCon 2015 EA)" "0.1.210 (SenchaCon 2015 EA)" -com.intellij.swift 144.SNAPSHOT \ No newline at end of file +com.intellij.swift 144.SNAPSHOT +SpellChecker 1.0 \ No newline at end of file diff --git a/platform/platform-resources/src/componentSets/VCS.xml b/platform/platform-resources/src/componentSets/VCS.xml index f76c7aee4d2d..7db8ceb7b6ca 100644 --- a/platform/platform-resources/src/componentSets/VCS.xml +++ b/platform/platform-resources/src/componentSets/VCS.xml @@ -32,6 +32,9 @@ com.intellij.openapi.vcs.changes.VcsEventWatcher + + com.intellij.openapi.vcs.annotate.AnnotationsPreloader + com.intellij.openapi.vcs.impl.VcsDirectoryMappingStorage diff --git a/platform/platform-tests/testData/editor/painting/borderAtLastLine.png b/platform/platform-tests/testData/editor/painting/borderAtLastLine.png new file mode 100644 index 000000000000..c218b16fb760 Binary files /dev/null and b/platform/platform-tests/testData/editor/painting/borderAtLastLine.png differ diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java index d865794235bb..43c0752075e4 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorPaintingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -86,6 +86,12 @@ public class EditorPaintingTest extends AbstractEditorTest { ((EditorEx)myEditor).setPrefixTextAndAttributes(">", new TextAttributes(Color.blue, Color.gray, null, null, Font.PLAIN)); checkResult(); } + + public void testBorderAtLastLine() throws Exception { + initText("a\nbc"); + addBorderHighlighter(3, 4, HighlighterLayer.WARNING, Color.red); + checkResult(); + } private static void addRangeHighlighter(int startOffset, int endOffset, int layer, Color foregroundColor, Color backgroundColor) { addRangeHighlighter(startOffset, endOffset, layer, new TextAttributes(foregroundColor, backgroundColor, null, null, Font.PLAIN)); diff --git a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java index 69a416aaa90d..172afcafe4aa 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilTest.java @@ -19,7 +19,6 @@ package com.intellij.util.containers; import com.intellij.openapi.util.Condition; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.ThrowableRunnable; import gnu.trove.TIntArrayList; import junit.framework.TestCase; @@ -228,19 +227,19 @@ public class ContainerUtilTest extends TestCase { } public void testCOWListPerformanceAdd() { - PlatformTestUtil.startPerformanceTest("COWList add", 3000, new ThrowableRunnable() { - @Override - public void run() throws Throwable { - List my = ContainerUtil.createLockFreeCopyOnWriteList(); - long start = System.currentTimeMillis(); + List my = ContainerUtil.createLockFreeCopyOnWriteList(); + PlatformTestUtil.startPerformanceTest("COWList add", 3000, () -> { + List local = my; + for (int it=0; it<10; it++) { + local.clear(); for (int i = 0; i < 15000; i++) { - my.add(i); - assertEquals(i, my.indexOf(i)); + local.add(i); } - long elapsed = System.currentTimeMillis() - start; - System.out.println("elapsed = " + elapsed); } }).useLegacyScaling().assertTiming(); + for (int i = 0; i < my.size(); i++) { + assertEquals(i, my.get(i)); + } } private static void assertReallyEmpty(List my) { diff --git a/platform/script-debugger/debugger-ui/script-debugger-ui.iml b/platform/script-debugger/debugger-ui/script-debugger-ui.iml index f77248634d16..ba1252cdc860 100644 --- a/platform/script-debugger/debugger-ui/script-debugger-ui.iml +++ b/platform/script-debugger/debugger-ui/script-debugger-ui.iml @@ -1,6 +1,6 @@ - + diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/DebuggableRunConfiguration.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/DebuggableRunConfiguration.java index 3c8c92fdd8a6..dadad5f64b31 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/DebuggableRunConfiguration.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/DebuggableRunConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,16 +20,26 @@ import com.intellij.execution.ExecutionResult; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.util.net.NetUtils; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugSession; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; public interface DebuggableRunConfiguration extends RunConfiguration { @NotNull - InetSocketAddress computeDebugAddress() throws ExecutionException; + default InetSocketAddress computeDebugAddress() throws ExecutionException { + try { + return new InetSocketAddress(InetAddress.getLoopbackAddress(), NetUtils.findAvailableSocketPort()); + } + catch (IOException e) { + throw new ExecutionException("Cannot find available port", e); + } + } @NotNull XDebugProcess createDebugProcess(@NotNull InetSocketAddress socketAddress, diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/RemoteDebugConfiguration.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/RemoteDebugConfiguration.java index d4102e79f7f2..3ffe0d6a022c 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/RemoteDebugConfiguration.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/RemoteDebugConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -31,7 +31,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.GuiUtils; import com.intellij.ui.PortField; import com.intellij.util.ThreeState; -import com.intellij.util.net.NetUtils; import com.intellij.util.ui.FormBuilder; import com.intellij.util.xmlb.SerializationFilter; import com.intellij.util.xmlb.SkipEmptySerializationFilter; @@ -42,6 +41,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.net.InetAddress; import java.net.InetSocketAddress; public abstract class RemoteDebugConfiguration extends LocatableConfigurationBase implements RunConfigurationWithSuppressedDefaultRunAction, DebuggableRunConfiguration { @@ -129,7 +129,7 @@ public abstract class RemoteDebugConfiguration extends LocatableConfigurationBas @Override public InetSocketAddress computeDebugAddress() { if (host == null) { - return new InetSocketAddress(NetUtils.getLoopbackAddress(), port); + return new InetSocketAddress(InetAddress.getLoopbackAddress(), port); } else { return new InetSocketAddress(host, getPort()); diff --git a/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt b/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt index 3d3a5e18c45c..408adc2e4f1a 100644 --- a/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt +++ b/platform/testFramework/src/com/intellij/testFramework/FixtureRule.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -232,8 +232,8 @@ inline fun Project.runInLoadComponentStateMode(task: () -> T): T { class DisposeNonLightProjectsRule() : ExternalResource() { override fun after() { - val projectManager = ProjectManager.getInstance() as ProjectManagerImpl - projectManager.openProjects.forEachGuaranteed { + val projectManager = if (ApplicationManager.getApplication().isDisposed) null else ProjectManager.getInstance() as ProjectManagerImpl + projectManager?.openProjects?.forEachGuaranteed { if (!ProjectManagerImpl.isLight(it)) { runInEdtAndWait { projectManager.closeProject(it, false, true, false) } } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 2272a8c1df7e..d7f87bf55f30 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -247,6 +247,7 @@ compiler.build.data.unused.threshold=30 compiler.build.data.unused.threshold.description=If project is not opened for the specified number of days, its build data will be cleared to save disk space vcs.show.colored.annotations=true +vcs.annotations.preload=false vcs.showConsole=true vcs.log.bek.sort=true vcs.log.bek.sort.disabled=false diff --git a/platform/util/src/com/intellij/openapi/diagnostic/FrequentEventDetector.java b/platform/util/src/com/intellij/openapi/diagnostic/FrequentEventDetector.java index fda9a025efc4..3e790a9b776a 100644 --- a/platform/util/src/com/intellij/openapi/diagnostic/FrequentEventDetector.java +++ b/platform/util/src/com/intellij/openapi/diagnostic/FrequentEventDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -53,7 +53,7 @@ public class FrequentEventDetector { myLevel = level; } - public void eventHappened() { + public void eventHappened(@NotNull Object event) { if (myEventsPosted.incrementAndGet() > myEventCountThreshold) { boolean shouldLog = false; @@ -75,12 +75,14 @@ public class FrequentEventDetector { logTrace = existingTraceId == null; if (logTrace) { myRecentTraces.put(trace, traceId = myLastTraceId.incrementAndGet()); - } else { + } + else { traceId = existingTraceId; } } - String message = "Too many events posted, #" + traceId + (logTrace ? "\n" + trace : ""); + String message = "Too many events posted, #" + traceId + ". Event: "+event + + (logTrace ? "\n" + trace : ""); if (myLevel == Level.INFO) { LOG.info(message); } diff --git a/platform/util/src/com/intellij/ui/JBAutoscroller.java b/platform/util/src/com/intellij/ui/JBAutoscroller.java index 5c37efbb4009..cb1af49a8917 100644 --- a/platform/util/src/com/intellij/ui/JBAutoscroller.java +++ b/platform/util/src/com/intellij/ui/JBAutoscroller.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -35,7 +35,7 @@ public class JBAutoscroller implements ActionListener { private static final Key SCROLL_HANDLER_KEY = Key.create("JBAutoScroller.AutoScrollHandler"); private static final JBAutoscroller INSTANCE = new JBAutoscroller(); - private final Timer myTimer = new Timer(SCROLL_UPDATE_INTERVAL, this); + private final Timer myTimer = UIUtil.createNamedTimer("JBAutoScroller",SCROLL_UPDATE_INTERVAL, this); private final DefaultScrollDeltaProvider myDefaultAutoScrollHandler = new DefaultScrollDeltaProvider(); private SyntheticDragEvent myLatestDragEvent; diff --git a/platform/util/src/com/intellij/util/PausesStat.java b/platform/util/src/com/intellij/util/PausesStat.java index baef6f2123b7..20ab5bfd86db 100644 --- a/platform/util/src/com/intellij/util/PausesStat.java +++ b/platform/util/src/com/intellij/util/PausesStat.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; public class PausesStat { private static final int N_MAX = 200000; + // stores pairs of (timestamp of the event start), (timestamp of the event end). Timestamps are stored as diffs between System.currentTimeMillis() and epochStart. private final TIntArrayList pauses = new TIntArrayList(); private final long epochStart; @NotNull private final String myName; diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 137bf178cc02..4a17db0d3c82 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -3020,6 +3020,7 @@ public class UIUtil { return c instanceof JFrame || c instanceof JDialog || c instanceof JWindow || c instanceof JRootPane || isFocusProxy(c); } + @NotNull public static Timer createNamedTimer(@NonNls @NotNull final String name, int delay, @NotNull ActionListener listener) { return new Timer(delay, listener) { @Override @@ -3028,6 +3029,15 @@ public class UIUtil { } }; } + @NotNull + public static Timer createNamedTimer(@NonNls @NotNull final String name, int delay) { + return new Timer(delay, null) { + @Override + public String toString() { + return name; + } + }; + } public static boolean isDialogRootPane(JRootPane rootPane) { if (rootPane != null) { diff --git a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java index bacb8ba9e42e..a10f34645ab6 100644 --- a/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java +++ b/platform/vcs-api/src/com/intellij/openapi/localVcs/UpToDateLineNumberProvider.java @@ -17,6 +17,7 @@ package com.intellij.openapi.localVcs; public interface UpToDateLineNumberProvider { int ABSENT_LINE_NUMBER = -1; + int FAKE_LINE_NUMBER = -2; int getLineNumber(int currentNumber); boolean isLineChanged(int currentNumber); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java index fb977eff25bd..7faa7b585e98 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java @@ -503,12 +503,12 @@ public class AnnotateDiffViewerAction extends ToggleAction implements DumbAware @Override public int getLineNumber(int currentNumber) { int number = myViewer.transferLineFromOnesideStrict(mySide, currentNumber); - return number != -1 ? myLocalChangesProvider.getLineNumber(number) : -1; + return number != -1 ? myLocalChangesProvider.getLineNumber(number) : FAKE_LINE_NUMBER; } @Override public boolean isLineChanged(int currentNumber) { - return getLineNumber(currentNumber) == -1; + return getLineNumber(currentNumber) == ABSENT_LINE_NUMBER; } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java index 476f63865f6a..16e6cebd6cc3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java @@ -1,10 +1,13 @@ package com.intellij.openapi.vcs.actions; import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.annotate.FileAnnotation; import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,6 +18,7 @@ import java.util.Map; class AnnotatePreviousRevisionAction extends AnnotateRevisionAction { @Nullable private final List myRevisions; + @Nullable private final VcsFileRevision myLastRevision; public AnnotatePreviousRevisionAction(@NotNull FileAnnotation annotation, @NotNull AbstractVcs vcs) { super("Annotate Previous Revision", "Annotate successor of selected revision in new tab", AllIcons.Actions.Annotate, @@ -22,6 +26,7 @@ class AnnotatePreviousRevisionAction extends AnnotateRevisionAction { List revisions = annotation.getRevisions(); if (revisions == null) { myRevisions = null; + myLastRevision = null; return; } @@ -36,6 +41,8 @@ class AnnotatePreviousRevisionAction extends AnnotateRevisionAction { for (int i = 0; i < annotation.getLineCount(); i++) { myRevisions.add(map.get(annotation.getLineRevisionNumber(i))); } + + myLastRevision = ContainerUtil.getFirstItem(revisions); } @Override @@ -43,4 +50,13 @@ class AnnotatePreviousRevisionAction extends AnnotateRevisionAction { public List getRevisions() { return myRevisions; } + + @Nullable + @Override + protected VcsFileRevision getFileRevision(@NotNull AnActionEvent e) { + if (getCurrentLine() == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) { + return myLastRevision; + } + return super.getFileRevision(e); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java index 024bcbce4ae2..baad9ad8a236 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java @@ -98,4 +98,8 @@ abstract class AnnotateRevisionAction extends AnnotateRevisionActionBase impleme public void consume(Integer integer) { currentLine = integer; } + + public int getCurrentLine() { + return currentLine; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java index 52ce811f0cd7..ccc1e57846da 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java @@ -40,31 +40,31 @@ public class AnnotationGutterLineConvertorProxy implements ActiveAnnotationGutte public String getLineText(int line, Editor editor) { int currentLine = myGetUpToDateLineNumber.getLineNumber(line); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return ""; + if (!canBeAnnotated(currentLine)) return ""; return myDelegate.getLineText(currentLine, editor); } public String getToolTip(int line, Editor editor) { int currentLine = myGetUpToDateLineNumber.getLineNumber(line); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return ""; + if (!canBeAnnotated(currentLine)) return ""; return myDelegate.getToolTip(currentLine, editor); } public EditorFontType getStyle(int line, Editor editor) { int currentLine = myGetUpToDateLineNumber.getLineNumber(line); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return EditorFontType.PLAIN; + if (!canBeAnnotated(currentLine)) return EditorFontType.PLAIN; return myDelegate.getStyle(currentLine, editor); } public ColorKey getColor(int line, Editor editor) { int currentLine = myGetUpToDateLineNumber.getLineNumber(line); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return AnnotationSource.LOCAL.getColor(); + if (!canBeAnnotated(currentLine)) return AnnotationSource.LOCAL.getColor(); return myDelegate.getColor(currentLine, editor); } public Color getBgColor(int line, Editor editor) { int currentLine = myGetUpToDateLineNumber.getLineNumber(line); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return null; + if (!canBeAnnotated(currentLine)) return null; return myDelegate.getBgColor(currentLine, editor); } @@ -78,13 +78,17 @@ public class AnnotationGutterLineConvertorProxy implements ActiveAnnotationGutte public void doAction(int lineNum) { int currentLine = myGetUpToDateLineNumber.getLineNumber(lineNum); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return; + if (!canBeAnnotated(currentLine)) return; myDelegate.doAction(currentLine); } public Cursor getCursor(int lineNum) { int currentLine = myGetUpToDateLineNumber.getLineNumber(lineNum); - if (currentLine == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) return Cursor.getDefaultCursor(); + if (!canBeAnnotated(currentLine)) return Cursor.getDefaultCursor(); return myDelegate.getCursor(currentLine); } + + private static boolean canBeAnnotated(int currentLine) { + return currentLine >= 0; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/AnnotationsPreloader.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/AnnotationsPreloader.java new file mode 100644 index 000000000000..59d692752cce --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/AnnotationsPreloader.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2016 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.openapi.vcs.annotate; + +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.FileEditorManagerAdapter; +import com.intellij.openapi.fileEditor.FileEditorManagerListener; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Alarm; +import org.jetbrains.annotations.NotNull; + +/** + * @author egor + */ +public class AnnotationsPreloader { + private final Alarm myAlarm; + + public AnnotationsPreloader(final Project project) { + myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, project); + + project.getMessageBus().connect(project).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { + @Override + public void fileOpened(@NotNull FileEditorManager source, @NotNull final VirtualFile file) { + if (!Registry.is("vcs.annotations.preload")) return; + + AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file); + if (vcs == null) return; + final AnnotationProvider annotationProvider = vcs.getCachingAnnotationProvider(); + assert annotationProvider != null; + + myAlarm.addRequest(new Runnable() { + @Override + public void run() { + try { + annotationProvider.annotate(file); + } + catch (VcsException ignore) { + } + } + }, 0); + } + }); + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java index 19f28961b96a..a1762dbc1ab0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.ex.LineStatusTracker; import com.intellij.openapi.vcs.ex.Range; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -104,8 +105,7 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide return content; } - private static int calcLineNumber(LineStatusTracker tracker, int currentNumber){ - if (tracker == null) return -1; + private static int calcLineNumber(@NotNull LineStatusTracker tracker, int currentNumber) { List ranges = tracker.getRanges(); int result = currentNumber; diff --git a/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java b/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java new file mode 100644 index 000000000000..aff4c81c0b36 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java @@ -0,0 +1,174 @@ +/* + * Copyright 2000-2016 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.codeInspection; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.LambdaRefactoringUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLocalInspectionTool { + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + + @Override + public void visitMethodReferenceExpression(final PsiMethodReferenceExpression expression) { + doCheckMethodCallOnFunctionalExpression(expression, new Condition() { + @Override + public boolean value(PsiElement element) { + return expression.resolve() != null; + } + }); + } + + @Override + public void visitLambdaExpression(final PsiLambdaExpression expression) { + doCheckMethodCallOnFunctionalExpression(expression, new Condition() { + @Override + public boolean value(PsiElement ggParent) { + final PsiElement body = expression.getBody(); + if (!(body instanceof PsiCodeBlock) || + ((PsiCodeBlock)body).getStatements().length == 1) { + return true; + } + if (LambdaUtil.getReturnExpressions(expression).size() > 1) { + return false; + } + final PsiElement callParent = ggParent.getParent(); + return callParent instanceof PsiStatement || + callParent instanceof PsiLocalVariable; + } + }); + } + + private void doCheckMethodCallOnFunctionalExpression(PsiFunctionalExpression expression, + Condition elementContainerCondition) { + final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); + if (parent instanceof PsiTypeCastExpression) { + final PsiElement gParent = PsiUtil.skipParenthesizedExprUp(parent.getParent()); + if (gParent instanceof PsiReferenceExpression) { + final PsiElement ggParent = gParent.getParent(); + if (ggParent instanceof PsiMethodCallExpression) { + final PsiMethod resolveMethod = ((PsiMethodCallExpression)ggParent).resolveMethod(); + final PsiElement referenceNameElement = ((PsiMethodCallExpression)ggParent).getMethodExpression().getReferenceNameElement(); + if (resolveMethod != null && + resolveMethod.getParameterList().getParametersCount() == 0 && //todo pass args as parameters + resolveMethod == LambdaUtil.getFunctionalInterfaceMethod(((PsiTypeCastExpression)parent).getType()) && + referenceNameElement != null && + elementContainerCondition.value(ggParent)) { + final ReplaceWithLambdaBodyFix fix = + new ReplaceWithLambdaBodyFix("Replace method call " + + (expression instanceof PsiLambdaExpression ? "on lambda with lambda body" + : "on method reference with corresponding method call")); + holder.registerProblem(referenceNameElement, "Method call can be simplified", fix); + } + } + } + } + } + }; + } + + private static class ReplaceWithLambdaBodyFix implements LocalQuickFix { + private String myName; + + public ReplaceWithLambdaBodyFix(String name) { + myName = name; + } + + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return myName; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class); + if (callExpression != null) { + final PsiExpression qualifierExpression = PsiUtil.skipParenthesizedExprDown(callExpression.getMethodExpression().getQualifierExpression()); + if (qualifierExpression instanceof PsiTypeCastExpression) { + final PsiExpression element = ((PsiTypeCastExpression)qualifierExpression).getOperand(); + if (element instanceof PsiLambdaExpression) { + replaceWithLambdaBody(callExpression, (PsiLambdaExpression)element); + } + else if (element instanceof PsiMethodReferenceExpression) { + final PsiLambdaExpression lambdaExpression = + LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)element, false, true); + replaceWithLambdaBody(callExpression, lambdaExpression); + } + } + } + } + + private static void replaceWithLambdaBody(PsiMethodCallExpression callExpression, PsiLambdaExpression element) { + final PsiElement body = element.getBody(); + if (body instanceof PsiExpression) { + callExpression.replace(body); + } + else if (body instanceof PsiCodeBlock) { + final PsiElement parent = callExpression.getParent(); + if (parent instanceof PsiStatement) { + final PsiElement gParent = parent.getParent(); + for (PsiStatement statement : ((PsiCodeBlock)body).getStatements()) { + PsiElement toInsert; + if (statement instanceof PsiReturnStatement) { + toInsert = ((PsiReturnStatement)statement).getReturnValue(); + } + else { + toInsert = statement; + } + + if (toInsert != null) { + gParent.addBefore(toInsert, parent); + } + } + parent.delete(); + } + else { + final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); + if (statements.length > 0) { + final PsiStatement anchor = PsiTreeUtil.getParentOfType(parent, PsiStatement.class); + if (anchor != null) { + final PsiElement gParent = anchor.getParent(); + for (int i = 0; i < statements.length - 1; i++) { + gParent.addBefore(statements[i], anchor); + } + } + final PsiExpression returnValue = ((PsiReturnStatement)statements[statements.length - 1]).getReturnValue(); + if (returnValue != null) { + callExpression.replace(returnValue); + } + } + } + } + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java index ab167af90564..7a81831a0c9f 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java @@ -15,34 +15,17 @@ */ package com.siyeh.ipp.types; -import com.intellij.codeInspection.RedundantLambdaCodeBlockInspection; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; -import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.RedundantCastUtil; -import com.intellij.refactoring.introduceField.ElementToWorkOn; -import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler; -import com.intellij.util.Function; -import com.intellij.util.text.UniqueNameGenerator; -import com.siyeh.ig.psiutils.SideEffectChecker; +import com.intellij.refactoring.util.LambdaRefactoringUtil; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class ReplaceMethodRefWithLambdaIntention extends Intention { private static final Logger LOG = Logger.getInstance("#" + ReplaceMethodRefWithLambdaIntention.class.getName()); @@ -59,10 +42,10 @@ public class ReplaceMethodRefWithLambdaIntention extends Intention { protected void processIntention(final Editor editor, @NotNull PsiElement element) { final PsiMethodReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(element, PsiMethodReferenceExpression.class); LOG.assertTrue(referenceExpression != null); - final PsiLambdaExpression expr = convertMethodReferenceToLambda(referenceExpression, false); + final PsiLambdaExpression expr = LambdaRefactoringUtil.convertMethodReferenceToLambda(referenceExpression, false, true); final Runnable runnable = new Runnable() { public void run() { - introduceQualifierAsLocalVariable(editor, expr); + LambdaRefactoringUtil.removeSideEffectsFromLambdaBody(editor, expr); } }; final Application application = ApplicationManager.getApplication(); @@ -73,221 +56,6 @@ public class ReplaceMethodRefWithLambdaIntention extends Intention { } } - public static PsiLambdaExpression convertMethodReferenceToLambda(final PsiMethodReferenceExpression referenceExpression, final boolean ignoreCast) { - final PsiElement resolve = referenceExpression.resolve(); - final PsiType functionalInterfaceType = referenceExpression.getFunctionalInterfaceType(); - final PsiClassType.ClassResolveResult functionalInterfaceResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); - LOG.assertTrue(interfaceMethod != null); - final PsiSubstitutor psiSubstitutor = LambdaUtil.getSubstitutor(interfaceMethod, functionalInterfaceResolveResult); - final MethodSignature signature = interfaceMethod.getSignature(psiSubstitutor); - final boolean isReceiver; - if (resolve instanceof PsiMethod){ - final PsiMethod method = (PsiMethod)resolve; - isReceiver = PsiMethodReferenceUtil.isResolvedBySecondSearch(referenceExpression, signature, - method.isVarArgs(), - method.hasModifierProperty(PsiModifier.STATIC), - method.getParameterList().getParametersCount()); - } - else { - isReceiver = false; - } - final PsiParameter[] psiParameters = resolve instanceof PsiMethod ? ((PsiMethod)resolve).getParameterList().getParameters() : null; - - final StringBuilder buf = new StringBuilder("("); - LOG.assertTrue(functionalInterfaceType != null); - buf.append(GenericsUtil.getVariableTypeByExpressionType(functionalInterfaceType).getCanonicalText()).append(")("); - final PsiParameterList parameterList = interfaceMethod.getParameterList(); - final PsiParameter[] parameters = parameterList.getParameters(); - - final Map map = new HashMap(); - final UniqueNameGenerator nameGenerator = new UniqueNameGenerator(); - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(referenceExpression.getProject()); - final String paramsString = StringUtil.join(parameters, new Function() { - @Override - public String fun(PsiParameter parameter) { - final int parameterIndex = parameterList.getParameterIndex(parameter); - String baseName; - if (isReceiver && parameterIndex == 0) { - final SuggestedNameInfo - nameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, psiSubstitutor.substitute(parameter.getType())); - baseName = nameInfo.names.length > 0 ? nameInfo.names[0] : parameter.getName(); - } - else { - final String initialName; - if (psiParameters != null) { - final int idx = parameterIndex - (isReceiver ? 1 : 0); - initialName = psiParameters.length > 0 ? psiParameters[idx < psiParameters.length ? idx : psiParameters.length - 1].getName() - : parameter.getName(); - } - else { - initialName = parameter.getName(); - } - baseName = codeStyleManager.variableNameToPropertyName(initialName, VariableKind.PARAMETER); - } - - if (baseName != null) { - String parameterName = nameGenerator.generateUniqueName(codeStyleManager.suggestUniqueVariableName(baseName, referenceExpression, true)); - map.put(parameter, parameterName); - return parameterName; - } - return ""; - } - }, ", "); - buf.append(paramsString); - buf.append(") -> "); - - - final JavaResolveResult resolveResult = referenceExpression.advancedResolve(false); - final PsiElement resolveElement = resolveResult.getElement(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(referenceExpression.getProject()); - if (resolveElement instanceof PsiMember) { - - buf.append("{"); - - if (!PsiType.VOID.equals(interfaceMethod.getReturnType())) { - buf.append("return "); - } - final PsiElement qualifier = referenceExpression.getQualifier(); - PsiClass containingClass = null; - if (resolveElement instanceof PsiMethod) { - containingClass = ((PsiMember)resolveElement).getContainingClass(); - LOG.assertTrue(containingClass != null); - } else if (resolveElement instanceof PsiClass) { - containingClass = (PsiClass)resolveElement; - } - - final boolean onArrayRef = - elementFactory.getArrayClass(PsiUtil.getLanguageLevel(referenceExpression)) == containingClass; - - final PsiElement referenceNameElement = referenceExpression.getReferenceNameElement(); - if (isReceiver){ - buf.append(map.get(parameters[0])).append("."); - } else { - if (!(referenceNameElement instanceof PsiKeyword)) { - if (qualifier instanceof PsiTypeElement) { - final PsiJavaCodeReferenceElement referenceElement = ((PsiTypeElement)qualifier).getInnermostComponentReferenceElement(); - LOG.assertTrue(referenceElement != null); - buf.append(referenceElement.getReferenceName()).append("."); - } - else if (qualifier != null && !(qualifier instanceof PsiThisExpression && ((PsiThisExpression)qualifier).getQualifier() == null)) { - buf.append(qualifier.getText()).append("."); - } - } - } - - //new or method name - buf.append(referenceExpression.getReferenceName()); - - if (referenceNameElement instanceof PsiKeyword) { - //class name - buf.append(" "); - if (onArrayRef) { - if (qualifier instanceof PsiTypeElement) { - final PsiType type = ((PsiTypeElement)qualifier).getType(); - int dim = type.getArrayDimensions(); - buf.append(type.getDeepComponentType().getCanonicalText()); - buf.append("["); - buf.append(map.get(parameters[0])); - buf.append("]"); - while (--dim > 0) { - buf.append("[]"); - } - } - } else { - buf.append(((PsiMember)resolveElement).getName()); - - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - - LOG.assertTrue(containingClass != null); - if (containingClass.hasTypeParameters() && !PsiUtil.isRawSubstitutor(containingClass, substitutor)) { - buf.append("<").append(StringUtil.join(containingClass.getTypeParameters(), new Function() { - @Override - public String fun(PsiTypeParameter parameter) { - final PsiType psiType = substitutor.substitute(parameter); - LOG.assertTrue(psiType != null); - return psiType.getCanonicalText(); - } - }, ", ")).append(">"); - } - } - } - - if (!onArrayRef || isReceiver) { - //param list - buf.append("("); - boolean first = true; - for (int i = isReceiver ? 1 : 0; i < parameters.length; i++) { - PsiParameter parameter = parameters[i]; - if (!first) { - buf.append(", "); - } else { - first = false; - } - buf.append(map.get(parameter)); - } - buf.append(")"); - } - - buf.append(";}"); - } - - - final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)referenceExpression.replace(elementFactory.createExpressionFromText(buf.toString(), referenceExpression)); - PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)typeCastExpression.getOperand(); - LOG.assertTrue(lambdaExpression != null, buf.toString()); - if (RedundantCastUtil.isCastRedundant(typeCastExpression) || ignoreCast) { - final PsiExpression operand = typeCastExpression.getOperand(); - LOG.assertTrue(operand != null); - lambdaExpression = (PsiLambdaExpression)typeCastExpression.replace(operand); - } - - final PsiElement body = lambdaExpression.getBody(); - final PsiExpression singleExpression = RedundantLambdaCodeBlockInspection.isCodeBlockRedundant(lambdaExpression, body); - if (singleExpression != null) { - body.replace(singleExpression); - } - - return lambdaExpression; - } - - private static void introduceQualifierAsLocalVariable(Editor editor, PsiLambdaExpression lambdaExpression) { - if (lambdaExpression != null && lambdaExpression.isValid()) { - final PsiElement body = lambdaExpression.getBody(); - PsiExpression methodCall = null; - if (body instanceof PsiCodeBlock) { - final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); - LOG.assertTrue(statements.length == 1); - final PsiStatement statement = statements[0]; - if (statement instanceof PsiReturnStatement) { - methodCall = ((PsiReturnStatement)statement).getReturnValue(); - } - else if (statement instanceof PsiExpressionStatement) { - methodCall = ((PsiExpressionStatement)statement).getExpression(); - } - } else { - methodCall = (PsiExpression)body; - } - PsiExpression qualifierExpression = null; - if (methodCall instanceof PsiMethodCallExpression) { - qualifierExpression = ((PsiMethodCallExpression)methodCall).getMethodExpression().getQualifierExpression(); - } - else if (methodCall instanceof PsiNewExpression) { - qualifierExpression = ((PsiNewExpression)methodCall).getQualifier(); - } - - if (qualifierExpression != null) { - final List sideEffects = new ArrayList(); - SideEffectChecker.checkSideEffects(qualifierExpression, sideEffects); - if (!sideEffects.isEmpty()) { - //ensure introduced before lambda - qualifierExpression.putUserData(ElementToWorkOn.PARENT, lambdaExpression); - new IntroduceVariableHandler().invoke(qualifierExpression.getProject(), editor, qualifierExpression); - } - } - } - } - private static class MethodRefPredicate implements PsiElementPredicate { @Override public boolean satisfiedBy(PsiElement element) { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java index a8fc04ccc9e8..e75418725733 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntConfigurationImpl.java @@ -197,6 +197,7 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis } private volatile Boolean myIsInitialized = null; + private volatile Thread myInitThread = null; public boolean isInitialized() { final Boolean initialized = myIsInitialized; @@ -667,7 +668,10 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis } private List getEventsByClass(Class eventClass) { - ensureInitialized(); + final Thread initThread = myInitThread; + if (initThread == null || initThread != Thread.currentThread()) { + ensureInitialized(); + } final List list = new ArrayList(); synchronized (myEventToTargetMap) { for (final ExecutionEvent event : myEventToTargetMap.keySet()) { @@ -716,6 +720,7 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { try { + myInitThread = Thread.currentThread(); // first, remove existing files final AntBuildFile[] currentFiles = getBuildFiles(); for (AntBuildFile file : currentFiles) { @@ -800,6 +805,7 @@ public class AntConfigurationImpl extends AntConfigurationBase implements Persis updateRegisteredActions(); } finally { + myInitThread = null; myIsInitialized = Boolean.TRUE; ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { diff --git a/plugins/git4idea/src/git4idea/commands/GitTask.java b/plugins/git4idea/src/git4idea/commands/GitTask.java index d4799bd2e776..d4c9e9bd8a22 100644 --- a/plugins/git4idea/src/git4idea/commands/GitTask.java +++ b/plugins/git4idea/src/git4idea/commands/GitTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -333,7 +333,7 @@ public class GitTask { } /** - * Does the work which is common for BackgrounableTask and ModalTask. + * Does the work which is common for BackgroundableTask and ModalTask. * Actually - starts a timer which checks if current progress indicator is cancelled. * If yes, kills the GitHandler. */ @@ -353,7 +353,7 @@ public class GitTask { public void run(ProgressIndicator indicator) { myIndicator = indicator; - myTimer = new Timer(); + myTimer = new Timer("Git task delegate"); myTimer.schedule(new TimerTask() { @Override public void run() { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java index b94a2bb524ef..c21a4adf0fde 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionMembersCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -321,26 +321,21 @@ public class GrTypeDefinitionMembersCache { if (traitFieldHelper == null) return; final VirtualFile virtualFile = traitFieldHelper.getContainingFile().getVirtualFile(); - FileBasedIndex.getInstance().processValues( + final List> descriptors = FileBasedIndex.getInstance().getValues( INDEX_ID, FileBasedIndex.getFileId(virtualFile), - virtualFile, - new FileBasedIndex.ValueProcessor>() { - @Override - public boolean process(VirtualFile file, Collection values) { - for (TraitFieldDescriptor descriptor : values) { - final GrLightField field = new GrLightField(trait, descriptor.name, descriptor.typeString); - if (descriptor.isStatic) { - field.getModifierList().addModifier(STATIC_MASK); - } - field.getModifierList().addModifier(descriptor.isPublic ? PUBLIC_MASK : PRIVATE_MASK); - addCandidate(field, substitutor); - } - return true; - } - }, trait.getResolveScope() ); + for (Collection traitFieldDescriptors : descriptors) { + for (TraitFieldDescriptor descriptor : traitFieldDescriptors) { + final GrLightField field = new GrLightField(trait, descriptor.name, descriptor.typeString); + if (descriptor.isStatic) { + field.getModifierList().addModifier(STATIC_MASK); + } + field.getModifierList().addModifier(descriptor.isPublic ? PUBLIC_MASK : PRIVATE_MASK); + addCandidate(field, substitutor); + } + } } } }.getResult(); diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitDebuggerRunner.java b/plugins/junit/src/com/intellij/execution/junit/JUnitDebuggerRunner.java index 2c6e2f613eb6..d0a5b221583f 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitDebuggerRunner.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitDebuggerRunner.java @@ -17,6 +17,7 @@ package com.intellij.execution.junit; import com.intellij.execution.JavaTestFrameworkDebuggerRunner; import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfiguration; import org.jetbrains.annotations.NotNull; /** @@ -25,7 +26,8 @@ import org.jetbrains.annotations.NotNull; public class JUnitDebuggerRunner extends JavaTestFrameworkDebuggerRunner { @Override protected boolean validForProfile(@NotNull RunProfile profile) { - return profile instanceof JUnitConfiguration; + return profile instanceof JUnitConfiguration || + profile instanceof JUnitTestDiscoveryConfiguration; } @NotNull diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 452dd932b9a8..a48926d97494 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -338,8 +338,9 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState list = perModule.get(module); if (list == null) { @@ -374,6 +375,10 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState myPatterns; + @Override protected void search() throws ExecutionException { - final Set patterns = TestDiscoverySearchHelper.search(getProject(), getPosition(), getChangeList(), getFrameworkPrefix()); - addClassesListToJavaParameters(patterns, FunctionUtil.id(), "", false, getJavaParameters()); + myPatterns = TestDiscoverySearchHelper.search(getProject(), getPosition(), getChangeList(), getFrameworkPrefix()); } @Override - protected void onFound() {} + protected void onFound() { + if (myPatterns != null) { + try { + addClassesListToJavaParameters(myPatterns, FunctionUtil.id(), "", false, getJavaParameters()); + } + catch (ExecutionException ignored) {} + } + } }; } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/RemovePropertyFix.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/RemovePropertyFix.java index e183e7ce5cc9..a72dd04baf62 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/RemovePropertyFix.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/RemovePropertyFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -21,42 +21,47 @@ import com.intellij.lang.properties.psi.Property; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; /** * @author cdr */ -public class RemovePropertyFix implements IntentionAction { +class RemovePropertyFix implements IntentionAction { private final Property myProperty; - public RemovePropertyFix(@NotNull final Property origProperty) { + RemovePropertyFix(@NotNull final Property origProperty) { myProperty = origProperty; } + @Override @NotNull public String getText() { return PropertiesBundle.message("remove.property.intention.text"); } + @Override @NotNull public String getFamilyName() { return getText(); } + @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return file.isValid() - && myProperty != null - && myProperty.isValid() - && myProperty.getManager().isInProject(myProperty) - ; + return file != null && + file.isValid() && + myProperty.isValid() && + PsiManager.getInstance(project).isInProject(myProperty); } + @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { if (!FileModificationService.getInstance().prepareFileForWrite(file)) return; myProperty.delete(); } + @Override public boolean startInWriteAction() { return true; } diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGDebuggerRunner.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGDebuggerRunner.java index 175f12a2ba3a..bdd14ce60176 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGDebuggerRunner.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGDebuggerRunner.java @@ -15,15 +15,17 @@ */ package com.theoryinpractice.testng.configuration; -import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.JavaTestFrameworkDebuggerRunner; +import com.intellij.execution.configurations.RunProfile; +import com.theoryinpractice.testng.configuration.testDiscovery.TestNGTestDiscoveryConfiguration; import org.jetbrains.annotations.NotNull; public class TestNGDebuggerRunner extends JavaTestFrameworkDebuggerRunner { @Override protected boolean validForProfile(@NotNull RunProfile profile) { - return profile instanceof TestNGConfiguration; + return profile instanceof TestNGConfiguration || + profile instanceof TestNGTestDiscoveryConfiguration; } @NotNull diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 0bc127bf2344..7562061f400a 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -23,7 +23,10 @@ import com.intellij.execution.configurations.ParametersList; import com.intellij.execution.process.*; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; -import com.intellij.execution.testframework.*; +import com.intellij.execution.testframework.Printable; +import com.intellij.execution.testframework.Printer; +import com.intellij.execution.testframework.TestFrameworkRunningModel; +import com.intellij.execution.testframework.TestSearchScope; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -36,6 +39,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.rt.execution.testFrameworks.ForkedDebuggerHelper; import com.intellij.util.PathUtil; @@ -239,38 +243,41 @@ public class TestNGRunnableState extends JavaTestFrameworkRunnableState> perModule = new TreeMap>(new Comparator() { - @Override - public int compare(Module o1, Module o2) { - return StringUtil.compare(o1.getName(), o2.getName(), true); - } - }); - - for (final PsiClass psiClass : myClasses.keySet()) { - final Module module = ModuleUtilCore.findModuleForPsiElement(psiClass); - if (module != null) { - List list = perModule.get(module); - if (list == null) { - list = new ArrayList(); - perModule.put(module, list); - } - list.add(psiClass.getQualifiedName()); - } - } - - try { - writeClassesPerModule(getConfiguration().getPackage(), getJavaParameters(), perModule); - } - catch (Exception e) { - LOG.error(e); - } - } + writeClassesPerModule(myClasses); } }; } + protected void writeClassesPerModule(Map>> classes) { + if (forkPerModule()) { + final Map> perModule = new TreeMap>(new Comparator() { + @Override + public int compare(Module o1, Module o2) { + return StringUtil.compare(o1.getName(), o2.getName(), true); + } + }); + + for (final PsiClass psiClass : classes.keySet()) { + final Module module = ModuleUtilCore.findModuleForPsiElement(psiClass); + if (module != null) { + List list = perModule.get(module); + if (list == null) { + list = new ArrayList(); + perModule.put(module, list); + } + list.add(psiClass.getQualifiedName()); + } + } + + try { + writeClassesPerModule(getConfiguration().getPackage(), getJavaParameters(), perModule); + } + catch (Exception e) { + LOG.error(e); + } + } + } + public static boolean supportSerializationProtocol(TestNGConfiguration config) { final Project project = config.getProject(); final GlobalSearchScope scopeToDetermineTestngIn; diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java index 5406f280093f..09efc7ef06aa 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java @@ -75,7 +75,17 @@ public class TestNGTestDiscoveryConfiguration extends TestDiscoveryConfiguration public TestNGTestDiscoveryRunnableState(ExecutionEnvironment environment) { super(environment, ((TestNGConfiguration)myDelegate)); } - + + @Override + protected TestSearchScope getScope() { + return TestSearchScope.MODULE_WITH_DEPENDENCIES; + } + + @Override + protected boolean forkPerModule() { + return spansMultipleModules(""); + } + @Override public SearchingForTestsTask createSearchingForTestsTask() { return new SearchingForTestsTask(myServerSocket, getConfiguration(), myTempFile, client) { @@ -89,6 +99,12 @@ public class TestNGTestDiscoveryConfiguration extends TestDiscoveryConfiguration TestNGTestPattern.fillTestObjects(myClasses, patterns, TestSearchScope.MODULE_WITH_DEPENDENCIES, TestNGTestDiscoveryConfiguration.this, searchScope); } + + @Override + protected void onFound() { + super.onFound(); + writeClassesPerModule(myClasses); + } }; } } diff --git a/plugins/testng_rt/src/org/testng/TestNGXmlSuiteHelper.java b/plugins/testng_rt/src/org/testng/TestNGXmlSuiteHelper.java index acc6d87c0753..6d9a4e9df101 100644 --- a/plugins/testng_rt/src/org/testng/TestNGXmlSuiteHelper.java +++ b/plugins/testng_rt/src/org/testng/TestNGXmlSuiteHelper.java @@ -24,7 +24,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -83,7 +82,8 @@ public class TestNGXmlSuiteHelper { try { OutputStream stream = new FileOutputStream(xmlFile, false); try { - stream.write(content.getBytes("UTF-8"), 0, content.length()); + byte[] text = content.getBytes("UTF-8"); + stream.write(text, 0, text.length); } finally { stream.close(); diff --git a/plugins/yaml/gen/org/jetbrains/yaml/lexer/_YAMLLexer.java b/plugins/yaml/gen/org/jetbrains/yaml/lexer/_YAMLLexer.java new file mode 100644 index 000000000000..1a172591fa42 --- /dev/null +++ b/plugins/yaml/gen/org/jetbrains/yaml/lexer/_YAMLLexer.java @@ -0,0 +1,1071 @@ +/* The following code was generated by JFlex 1.4.3 on 11/23/15 4:33 PM */ + +package org.jetbrains.yaml.lexer; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.yaml.YAMLTokenTypes; + +/* Auto generated File */ + +/** + * This class is a scanner generated by + * JFlex 1.4.3 + * on 11/23/15 4:33 PM from the specification file + * /Users/valich/work/idea/plugins/yaml/src/org/jetbrains/yaml/lexer/yaml.flex + */ +public class _YAMLLexer implements FlexLexer, YAMLTokenTypes { + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int VALUE_OR_KEY = 6; + public static final int VALUE_BRACE = 8; + public static final int YYINITIAL = 0; + public static final int BRACES = 2; + public static final int VALUE = 4; + public static final int INDENT_VALUE = 10; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 + }; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\11\0\1\10\1\1\2\0\1\2\22\0\1\13\1\27\1\21\1\6"+ + "\1\25\1\17\1\26\1\22\2\25\1\26\1\32\1\4\1\12\1\25"+ + "\1\25\12\23\1\7\1\25\1\30\1\25\1\14\1\5\1\26\6\23"+ + "\24\24\1\31\1\20\1\11\1\0\1\25\1\3\6\23\24\24\1\15"+ + "\1\33\1\16\1\25\u05e1\0\12\23\206\0\12\23\306\0\12\23\u019c\0"+ + "\12\23\166\0\12\23\166\0\12\23\166\0\12\23\166\0\12\23\166\0"+ + "\12\23\166\0\12\23\166\0\12\23\166\0\12\23\340\0\12\23\166\0"+ + "\12\23\106\0\12\23\u0116\0\12\23\106\0\12\23\u0746\0\12\23\46\0"+ + "\12\23\u012c\0\12\23\200\0\12\23\246\0\12\23\6\0\12\23\266\0"+ + "\12\23\126\0\12\23\206\0\12\23\6\0\12\23\u89c6\0\12\23\u02a6\0"+ + "\12\23\46\0\12\23\306\0\12\23\166\0\12\23\u0196\0\12\23\u5316\0"+ + "\12\23\346\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\16\0\1\1\1\2\1\3\1\4\1\5\1\6\1\3"+ + "\1\7\1\10\2\3\1\11\1\12\4\3\1\13\1\3"+ + "\1\1\1\5\2\3\1\11\1\3\1\1\1\5\5\3"+ + "\1\1\1\5\2\3\1\14\1\15\1\16\10\0\1\1"+ + "\1\0\1\17\1\0\2\20\2\21\2\22\6\0\1\23"+ + "\2\0\1\24\1\25\1\0\1\25\4\0\2\26\1\0"+ + "\1\1\1\0\1\17\3\0\1\1\4\0\1\23\1\24"+ + "\1\1\3\0\1\27\14\0\1\30\1\0\1\1\2\0"+ + "\1\31\3\0\1\32\1\0\1\1\5\0\1\1\2\0"+ + "\2\1\2\0\2\1\2\0\1\1\2\0\1\1\1\0"+ + "\1\1\3\0\2\1\1\0\4\1\1\0\1\1\2\0"+ + "\1\1"; + + private static int [] zzUnpackAction() { + int [] result = new int[170]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\34\0\70\0\124\0\160\0\214\0\250\0\304"+ + "\0\340\0\374\0\u0118\0\u0134\0\u0150\0\u016c\0\u0188\0\u01a4"+ + "\0\u01a4\0\u01a4\0\u01c0\0\u01dc\0\u01f8\0\u0214\0\u01a4\0\u0230"+ + "\0\u024c\0\u0268\0\u01a4\0\u0284\0\u02a0\0\u02bc\0\u02d8\0\u01a4"+ + "\0\u02f4\0\u0310\0\u032c\0\u0348\0\u0364\0\u0380\0\u039c\0\u03b8"+ + "\0\u03d4\0\u03f0\0\u03d4\0\u040c\0\u0428\0\u01c0\0\u0444\0\u0460"+ + "\0\u047c\0\u0460\0\u0498\0\u01a4\0\u04b4\0\u04d0\0\u01a4\0\u04ec"+ + "\0\u0508\0\u0524\0\u0540\0\u055c\0\u0578\0\u0594\0\u05b0\0\u05cc"+ + "\0\u0188\0\u01a4\0\u05e8\0\u01a4\0\u0604\0\u01a4\0\u0620\0\u063c"+ + "\0\u0658\0\u0674\0\u02a0\0\u040c\0\u0690\0\u06ac\0\u02bc\0\u0428"+ + "\0\u06c8\0\u01a4\0\u06e4\0\u0700\0\u071c\0\u0738\0\u0754\0\u0770"+ + "\0\u01a4\0\u078c\0\u07a8\0\u07c4\0\u07e0\0\u07fc\0\u0310\0\u0818"+ + "\0\u0834\0\u0850\0\u086c\0\u03d4\0\u03b8\0\u0888\0\u01a4\0\u08a4"+ + "\0\u08c0\0\u08dc\0\u0460\0\u0444\0\u01a4\0\u08f8\0\u0914\0\u0930"+ + "\0\u08f8\0\u094c\0\u0968\0\u0984\0\u0524\0\u09a0\0\u09bc\0\u055c"+ + "\0\u01a4\0\u01a4\0\u09d8\0\u09f4\0\u0a10\0\u0a2c\0\u01a4\0\u0a48"+ + "\0\u0a64\0\u0a80\0\u01a4\0\u0a9c\0\u0ab8\0\u0ad4\0\u0af0\0\u0b0c"+ + "\0\u0b28\0\u0b44\0\u0b60\0\u0b7c\0\u0b98\0\u0bb4\0\u0bd0\0\u0bec"+ + "\0\u09f4\0\u0c08\0\u0c24\0\u0c40\0\u0c5c\0\u0c78\0\u0c94\0\u0cb0"+ + "\0\u0ccc\0\u0ce8\0\u0d04\0\u0ab8\0\u0d20\0\u0d3c\0\u0d58\0\u0d74"+ + "\0\u0b60\0\u0d90\0\u0dac\0\u0dc8\0\u0de4\0\u0e00\0\u0e1c\0\u0c78"+ + "\0\u0e38\0\u0e54"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[170]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\17\1\20\2\21\1\22\1\23\1\24\1\25\1\26"+ + "\1\27\1\30\1\26\1\31\1\32\1\33\1\34\1\17"+ + "\1\35\1\36\3\17\1\21\1\37\1\17\1\40\1\17"+ + "\1\41\1\42\1\20\2\21\1\22\1\43\1\24\1\44"+ + "\1\26\1\27\1\45\1\26\1\21\1\46\1\33\1\47"+ + "\1\42\1\35\1\36\3\42\1\21\1\37\1\42\1\40"+ + "\1\42\1\21\1\50\1\20\2\21\1\22\1\51\1\24"+ + "\1\52\1\26\1\27\1\53\1\26\1\31\1\32\1\33"+ + "\1\34\1\50\1\54\1\55\3\50\1\21\1\37\1\50"+ + "\1\40\1\50\1\41\1\17\1\20\2\21\1\22\1\23"+ + "\1\24\1\25\1\26\1\27\1\56\1\26\1\31\1\32"+ + "\1\33\1\34\1\17\1\35\1\36\3\17\1\21\1\37"+ + "\1\17\1\40\1\17\1\41\1\57\1\20\2\21\1\22"+ + "\1\60\1\24\1\61\1\26\1\27\1\62\1\26\1\31"+ + "\1\46\1\33\1\47\1\57\1\54\1\55\3\57\1\21"+ + "\1\37\1\57\1\40\1\57\1\41\1\63\1\64\6\63"+ + "\1\65\2\63\1\65\20\63\27\0\1\66\5\0\1\67"+ + "\6\0\1\70\2\0\1\70\20\0\1\71\4\0\1\72"+ + "\1\0\1\72\2\0\1\72\5\0\1\71\2\0\3\71"+ + "\2\0\1\71\1\0\1\71\2\0\2\67\1\0\1\67"+ + "\3\0\2\67\1\0\1\67\1\0\2\67\12\0\1\67"+ + "\2\0\1\73\4\0\1\74\1\0\1\74\2\0\1\74"+ + "\5\0\1\73\2\0\3\73\2\0\1\73\1\0\1\73"+ + "\2\0\2\67\5\0\1\67\2\0\1\67\34\0\1\75"+ + "\52\0\1\75\1\76\2\0\3\76\1\77\1\100\1\101"+ + "\2\76\1\101\20\76\34\0\1\17\2\0\5\17\1\0"+ + "\2\17\1\0\20\17\1\24\1\0\32\24\1\17\1\102"+ + "\1\0\5\17\1\103\2\17\1\103\20\17\10\0\1\26"+ + "\2\0\1\26\20\0\1\17\1\104\1\0\5\17\1\105"+ + "\2\17\1\105\20\17\1\0\1\106\6\0\1\107\1\0"+ + "\1\110\1\107\16\0\1\110\16\0\1\111\33\0\1\112"+ + "\16\0\1\113\1\114\16\113\1\115\1\116\12\113\1\117"+ + "\1\120\20\117\1\121\11\117\1\0\1\122\3\0\3\123"+ + "\1\124\1\0\1\125\1\124\3\0\1\126\2\0\1\123"+ + "\2\125\2\123\1\127\1\130\1\0\1\123\2\0\1\131"+ + "\6\0\1\132\1\0\1\133\1\132\16\0\1\133\1\0"+ + "\1\134\2\0\1\134\1\135\1\134\1\135\1\136\1\137"+ + "\1\135\1\134\1\137\1\134\2\135\12\134\1\135\2\134"+ + "\1\42\2\0\1\42\1\0\3\42\2\0\1\42\1\0"+ + "\1\42\2\0\12\42\1\0\3\42\1\102\1\0\1\42"+ + "\1\0\3\42\1\103\1\0\1\42\1\103\1\42\2\0"+ + "\12\42\1\0\3\42\1\104\1\0\1\42\1\0\3\42"+ + "\1\105\1\0\1\42\1\105\1\42\2\0\12\42\1\0"+ + "\2\42\15\0\1\140\33\0\1\141\16\0\1\142\2\0"+ + "\3\142\1\143\1\144\1\145\2\142\1\145\20\142\1\50"+ + "\2\0\5\50\1\0\2\50\1\0\21\50\1\102\1\0"+ + "\5\50\1\103\2\50\1\103\20\50\20\114\1\146\1\147"+ + "\12\114\22\120\1\150\11\120\1\151\2\0\1\151\1\152"+ + "\1\151\1\152\1\153\1\154\1\152\1\151\1\154\1\151"+ + "\2\152\12\151\1\152\2\151\1\57\2\0\1\57\1\0"+ + "\3\57\2\0\1\57\1\0\1\57\2\0\12\57\1\0"+ + "\3\57\1\102\1\0\1\57\1\0\3\57\1\103\1\0"+ + "\1\57\1\103\1\57\2\0\12\57\1\0\2\57\1\63"+ + "\1\0\32\63\1\0\1\155\6\0\1\65\2\0\1\65"+ + "\25\0\3\156\2\0\1\157\4\0\1\160\2\0\1\156"+ + "\2\157\2\156\1\161\1\162\1\0\1\156\11\0\1\70"+ + "\2\0\1\70\20\0\1\163\2\0\1\163\1\164\1\163"+ + "\1\164\1\165\1\71\1\164\1\163\1\71\1\163\2\164"+ + "\12\163\1\164\2\163\1\71\2\0\1\71\1\0\3\71"+ + "\2\0\1\71\1\0\1\71\2\0\12\71\1\0\2\71"+ + "\1\166\2\0\3\166\1\167\1\170\1\73\2\166\1\73"+ + "\20\166\1\73\2\0\5\73\1\0\2\73\1\0\20\73"+ + "\12\0\1\171\17\0\1\171\1\0\1\76\2\0\4\76"+ + "\1\100\1\101\2\76\1\101\20\76\6\0\1\17\25\0"+ + "\1\17\2\172\5\17\1\172\2\17\1\172\20\17\10\0"+ + "\1\103\2\0\1\103\30\0\1\105\2\0\1\105\30\0"+ + "\1\107\2\0\1\107\21\0\1\106\6\0\1\107\2\0"+ + "\1\107\20\0\1\173\1\0\4\173\1\0\2\173\3\0"+ + "\1\173\2\0\12\173\1\0\2\173\1\174\1\0\3\112"+ + "\1\175\1\112\1\175\2\112\1\175\3\112\1\176\1\112"+ + "\1\174\2\112\3\174\2\112\1\174\1\112\1\174\1\112"+ + "\1\113\1\114\32\113\7\0\1\177\33\0\1\177\12\0"+ + "\1\117\12\0\1\122\3\0\3\123\1\124\1\0\1\123"+ + "\1\124\3\0\1\126\2\0\5\123\3\0\1\123\11\0"+ + "\1\124\2\0\1\124\21\0\1\122\3\0\3\123\1\124"+ + "\1\0\1\125\1\124\3\0\1\126\2\0\1\123\2\125"+ + "\2\123\1\127\2\0\1\123\24\0\1\200\15\0\3\123"+ + "\2\0\1\123\4\0\1\126\2\0\5\123\3\0\1\123"+ + "\5\0\4\201\1\0\2\201\4\0\1\202\2\0\6\201"+ + "\1\0\2\201\11\0\1\132\2\0\1\132\21\0\1\131"+ + "\6\0\1\132\2\0\1\132\20\0\1\134\2\0\1\134"+ + "\1\135\2\134\1\136\1\137\1\135\1\134\1\137\1\134"+ + "\2\135\12\134\1\135\2\134\6\0\1\42\25\0\1\42"+ + "\2\203\1\42\1\203\3\42\2\203\1\42\1\203\1\42"+ + "\2\203\12\42\1\203\2\42\1\204\1\0\4\204\1\0"+ + "\2\204\3\0\1\204\2\0\12\204\1\0\2\204\1\205"+ + "\1\0\3\141\1\206\1\141\1\206\2\141\1\206\3\141"+ + "\1\207\1\141\1\205\2\141\3\205\2\141\1\205\1\141"+ + "\1\205\1\141\1\142\2\0\4\142\1\144\1\145\2\142"+ + "\1\145\20\142\6\0\1\50\25\0\34\114\22\0\1\120"+ + "\11\0\1\151\2\0\1\151\1\152\2\151\1\153\1\154"+ + "\1\152\1\151\1\154\1\151\2\152\12\151\1\152\2\151"+ + "\6\0\1\57\32\0\3\156\2\0\1\156\4\0\1\160"+ + "\2\0\5\156\3\0\1\156\6\0\3\156\2\0\1\157"+ + "\4\0\1\160\2\0\1\156\2\157\2\156\1\161\2\0"+ + "\1\156\24\0\1\210\14\0\4\211\1\0\2\211\4\0"+ + "\1\212\2\0\6\211\1\0\2\211\1\0\1\163\2\0"+ + "\1\163\1\164\2\163\1\165\1\71\1\164\1\163\1\71"+ + "\1\163\2\164\12\163\1\164\2\163\6\0\1\71\25\0"+ + "\1\166\2\0\4\166\1\170\1\73\2\166\1\73\20\166"+ + "\6\0\1\73\25\0\1\213\1\0\3\173\1\214\1\0"+ + "\1\144\1\173\1\0\1\214\1\173\2\0\1\215\1\173"+ + "\1\213\2\173\3\213\2\173\1\213\1\0\1\213\1\173"+ + "\1\216\1\0\1\112\2\216\1\217\1\220\1\175\1\221"+ + "\1\216\1\217\1\221\2\216\1\222\15\216\1\174\1\0"+ + "\1\112\2\174\1\217\1\174\1\217\1\112\1\174\1\217"+ + "\1\112\2\174\1\223\15\174\1\50\4\0\1\144\1\0"+ + "\1\144\2\0\1\144\5\0\1\50\2\0\3\50\2\0"+ + "\1\50\1\0\1\50\24\0\1\123\14\0\4\201\1\0"+ + "\2\201\1\0\1\224\2\0\1\202\2\0\6\201\1\0"+ + "\2\201\24\0\1\225\10\0\1\226\1\0\3\204\1\227"+ + "\1\0\1\153\1\204\1\0\1\227\1\204\2\0\1\230"+ + "\1\204\1\226\2\204\3\226\2\204\1\226\1\0\1\226"+ + "\1\204\1\231\1\0\1\141\1\231\1\232\1\233\1\232"+ + "\1\206\1\234\1\232\1\233\1\234\1\231\1\232\1\235"+ + "\12\231\1\232\2\231\1\205\1\0\1\141\1\205\1\141"+ + "\1\233\1\205\1\233\2\141\1\233\1\141\1\205\1\141"+ + "\1\207\12\205\1\141\2\205\1\57\4\0\1\153\1\0"+ + "\1\153\2\0\1\153\5\0\1\57\2\0\3\57\2\0"+ + "\1\57\1\0\1\57\24\0\1\156\14\0\4\211\1\0"+ + "\2\211\1\0\1\171\2\0\1\212\2\0\6\211\1\0"+ + "\2\211\24\0\1\236\10\0\1\237\1\0\1\173\2\237"+ + "\1\240\1\143\1\144\1\241\1\142\1\240\1\241\2\142"+ + "\1\242\12\237\1\142\2\237\1\213\1\0\1\173\2\213"+ + "\1\240\1\50\1\243\1\173\1\50\1\240\1\173\2\50"+ + "\1\244\12\213\1\50\2\213\1\50\4\0\1\144\1\0"+ + "\1\144\2\0\1\144\3\0\1\176\1\0\1\50\2\0"+ + "\3\50\2\0\1\50\1\0\1\50\1\0\1\216\1\0"+ + "\1\112\2\216\1\217\1\216\1\175\1\221\1\216\1\217"+ + "\1\221\2\216\1\222\16\216\1\0\1\112\2\216\1\217"+ + "\1\216\1\217\1\221\1\216\1\217\1\221\2\216\1\222"+ + "\15\216\1\174\1\0\3\112\1\175\1\174\1\175\2\112"+ + "\1\175\3\112\1\176\1\112\1\174\2\112\3\174\2\112"+ + "\1\174\1\112\1\174\1\112\1\142\2\0\2\142\1\243"+ + "\1\142\1\144\1\145\1\142\1\243\1\145\21\142\2\0"+ + "\2\142\1\243\1\143\1\144\1\145\1\142\1\243\1\145"+ + "\20\142\1\0\1\122\6\0\1\124\2\0\1\124\43\0"+ + "\1\201\10\0\1\245\1\0\1\204\1\245\1\246\1\247"+ + "\1\152\1\153\1\250\1\152\1\247\1\250\1\151\1\152"+ + "\1\251\12\245\1\152\2\245\1\226\1\0\1\204\1\226"+ + "\1\204\1\247\1\57\1\252\1\204\1\0\1\247\1\204"+ + "\1\57\1\0\1\230\12\226\1\0\2\226\1\57\4\0"+ + "\1\153\1\0\1\153\2\0\1\153\3\0\1\207\1\0"+ + "\1\57\2\0\3\57\2\0\1\57\1\0\1\57\1\0"+ + "\1\231\1\0\1\141\1\231\1\232\1\233\1\231\1\206"+ + "\1\234\1\232\1\233\1\234\1\231\1\232\1\235\12\231"+ + "\1\232\2\231\1\205\1\0\3\141\1\206\1\205\1\206"+ + "\2\141\1\206\3\141\1\207\1\141\1\205\2\141\3\205"+ + "\2\141\1\205\1\141\1\205\1\141\1\231\1\0\1\141"+ + "\1\231\1\232\1\233\1\231\1\233\1\234\1\232\1\233"+ + "\1\234\1\231\1\232\1\235\12\231\1\232\2\231\1\57"+ + "\4\0\1\153\1\57\1\153\2\0\1\153\5\0\1\57"+ + "\2\0\3\57\2\0\1\57\1\0\1\57\24\0\1\211"+ + "\10\0\1\237\1\0\1\173\2\237\1\240\1\142\1\144"+ + "\1\241\1\142\1\240\1\241\2\142\1\242\12\237\1\142"+ + "\3\237\1\0\1\173\2\237\1\240\1\142\1\243\1\241"+ + "\1\142\1\240\1\241\2\142\1\242\12\237\1\142\2\237"+ + "\1\142\2\0\2\142\1\243\1\142\1\144\1\145\1\142"+ + "\1\243\1\145\2\142\1\222\16\142\2\0\4\142\1\243"+ + "\1\145\2\142\1\145\21\142\2\0\2\142\1\243\1\143"+ + "\1\144\1\145\1\142\1\243\1\145\2\142\1\222\15\142"+ + "\1\245\1\0\1\204\1\245\1\246\1\247\1\151\1\153"+ + "\1\250\1\152\1\247\1\250\1\151\1\152\1\251\12\245"+ + "\1\152\2\245\1\226\1\0\3\204\1\227\1\57\1\153"+ + "\1\204\1\0\1\227\1\204\2\0\1\230\1\204\1\226"+ + "\2\204\3\226\2\204\1\226\1\0\1\226\1\204\1\245"+ + "\1\0\1\204\1\245\1\246\1\247\1\151\1\252\1\250"+ + "\1\152\1\247\1\250\1\151\1\152\1\251\12\245\1\152"+ + "\2\245\1\57\4\0\1\153\1\57\1\153\2\0\1\153"+ + "\3\0\1\207\1\0\1\57\2\0\3\57\2\0\1\57"+ + "\1\0\1\57\1\0\1\151\2\0\1\151\1\152\2\151"+ + "\1\252\1\154\1\152\1\151\1\154\1\151\2\152\12\151"+ + "\1\152\2\151"; + + private static int [] zzUnpackTrans() { + int [] result = new int[3696]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + private static final char[] EMPTY_BUFFER = new char[0]; + private static final int YYEOF = -1; + private static java.io.Reader zzReader = null; // Fake + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\16\0\1\1\3\11\4\1\1\11\3\1\1\11\4\1"+ + "\1\11\23\1\1\11\2\1\1\11\1\1\4\0\2\1"+ + "\1\0\1\1\1\0\1\11\1\1\1\11\1\1\1\11"+ + "\1\1\6\0\1\1\2\0\1\1\1\11\1\0\1\1"+ + "\4\0\1\11\1\1\1\0\1\1\1\0\1\1\3\0"+ + "\1\1\4\0\1\11\2\1\3\0\1\11\2\1\5\0"+ + "\1\1\2\0\1\1\2\11\1\0\1\1\2\0\1\11"+ + "\3\0\1\11\1\0\1\1\5\0\1\1\2\0\2\1"+ + "\2\0\2\1\2\0\1\1\2\0\1\1\1\0\1\1"+ + "\3\0\2\1\1\0\4\1\1\0\1\1\2\0\1\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[170]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private CharSequence zzBuffer = ""; + + /** this buffer may contains the current text array to be matched when it is cheap to acquire it */ + private char[] zzBufferArray; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the textposition at the last state to be included in yytext */ + private int zzPushbackPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /** For the backwards DFA of general lookahead statements */ + private boolean [] zzFin = new boolean [ZZ_BUFFERSIZE+1]; + + /** denotes if the user-EOF-code has already been executed */ + private boolean zzEOFDone; + + /* user code: */ + private int currentLineIndent = 0; + private int valueIndent = -1; + private int braceCount = 0; + private IElementType valueTokenType = null; + private int previousState = YYINITIAL; + + public boolean isCleanState() { + return yystate() == YYINITIAL + && currentLineIndent == 0 + && braceCount == 0; + } + + public void cleanMyState() { + currentLineIndent = 0; + braceCount = 0; + } + + private char previousChar() { + return getChar(-1); + } + + private char getChar(final int offset) { + final int loc = getTokenStart() + offset; + return 0 <= loc && loc < zzBuffer.length() ? zzBuffer.charAt(loc) : (char) -1; + } + + private char getCharAfter(final int offset) { + final int loc = getTokenEnd() + offset; + return 0 <= loc && loc < zzBuffer.length() ? zzBuffer.charAt(loc) : (char) -1; + } + + private IElementType getWhitespaceTypeAndUpdateIndent() { + if (isAfterEol()) { + currentLineIndent = yylength(); + return INDENT; + } + else { + return WHITESPACE; + } + } + + private boolean isAfterEol() { + final char prev = previousChar(); + return prev == (char)-1 || prev == '\n'; + } + + private boolean isAfterSpace() { + final char prev = previousChar(); + return prev == (char)-1 || prev == '\t' || prev == ' '; + } + + private void yyBegin(int newState) { + //System.out.println("yybegin(): " + newState); + yybegin(newState); + } + + private boolean startsWith(CharSequence haystack, CharSequence needle) { + for (int i = Math.min(haystack.length(), needle.length()) - 1; i >= 0; i--) { + if (haystack.charAt(i) != needle.charAt(i)) { + return false; + } + } + return true; + } + + private IElementType tokenOrForbidden(IElementType tokenType) { + if (!isAfterEol() || yylength() < 3) { + return tokenType; + } + + if (startsWith(yytext(), "---")) { + braceCount = 0; + yyBegin(YYINITIAL); + yypushback(yylength() - 3); + return DOCUMENT_MARKER; + } + if (startsWith(yytext(), "...")) { + braceCount = 0; + yyBegin(YYINITIAL); + yypushback(yylength() - 3); + return DOCUMENT_END; + } + return tokenType; + } + + + /** + * Creates a new scanner + * + * @param in the java.io.Reader to read input from. + */ + public _YAMLLexer(java.io.Reader in) { + this.zzReader = in; + } + + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 224) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + public final int getTokenStart(){ + return zzStartRead; + } + + public final int getTokenEnd(){ + return getTokenStart() + yylength(); + } + + public void reset(CharSequence buffer, int start, int end,int initialState){ + zzBuffer = buffer; + zzBufferArray = null; + zzCurrentPos = zzMarkedPos = zzStartRead = start; + zzPushbackPos = 0; + zzAtEOF = false; + zzAtBOL = true; + zzEndRead = end; + yybegin(initialState); + } + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + return true; + } + + + /** + * Returns the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + public final CharSequence yytext() { + return zzBuffer.subSequence(zzStartRead, zzMarkedPos); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBufferArray != null ? zzBufferArray[zzStartRead+pos]:zzBuffer.charAt(zzStartRead+pos); + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Contains user EOF-code, which will be executed exactly once, + * when the end of file is reached + */ + private void zzDoEOF() { + if (!zzEOFDone) { + zzEOFDone = true; + + } + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + */ + public IElementType advance() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + CharSequence zzBufferL = zzBuffer; + char[] zzBufferArrayL = zzBufferArray; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = ZZ_LEXSTATE[zzLexicalState]; + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++)); + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzCurrentPosL++] : zzBufferL.charAt(zzCurrentPosL++)); + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 23: + // lookahead expression with fixed lookahead length + yypushback(1); + { return getWhitespaceTypeAndUpdateIndent(); + } + case 27: break; + case 7: + { return getWhitespaceTypeAndUpdateIndent(); + } + case 28: break; + case 1: + { return tokenOrForbidden(TEXT); + } + case 29: break; + case 26: + // general lookahead, find correct zzMarkedPos + { int zzFState = 8; + int zzFPos = zzStartRead; + if (zzFin.length <= (zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())) { zzFin = new boolean[(zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())+1]; } + boolean zzFinL[] = zzFin; + while (zzFState != -1 && zzFPos < zzMarkedPos) { + zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1); + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzFPos++] : zzBufferL.charAt(zzFPos++)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + } + if (zzFState != -1) { zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1); } + while (zzFPos <= zzMarkedPos) { + zzFinL[zzFPos++] = false; + } + + zzFState = 9; + zzFPos = zzMarkedPos; + while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[--zzFPos] : zzBufferL.charAt(--zzFPos)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + }; + zzMarkedPos = zzFPos; + } + { yyBegin(VALUE_BRACE); + return SCALAR_KEY; + } + case 30: break; + case 21: + // general lookahead, find correct zzMarkedPos + { int zzFState = 6; + int zzFPos = zzStartRead; + if (zzFin.length <= (zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())) { zzFin = new boolean[(zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())+1]; } + boolean zzFinL[] = zzFin; + while (zzFState != -1 && zzFPos < zzMarkedPos) { + zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1); + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzFPos++] : zzBufferL.charAt(zzFPos++)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + } + if (zzFState != -1) { zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1); } + while (zzFPos <= zzMarkedPos) { + zzFinL[zzFPos++] = false; + } + + zzFState = 7; + zzFPos = zzMarkedPos; + while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[--zzFPos] : zzBufferL.charAt(--zzFPos)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + }; + zzMarkedPos = zzFPos; + } + { return TAG; + } + case 31: break; + case 25: + { return SCALAR_KEY; + } + case 32: break; + case 5: + { return QUESTION; + } + case 33: break; + case 15: + { if (zzMarkedPos == zzEndRead){ + return SCALAR_KEY; + } + yyBegin(VALUE); + return tokenOrForbidden(TEXT); + } + case 34: break; + case 9: + { braceCount++; + if (braceCount != 0 && yystate() != BRACES) { + previousState = yystate(); + } + yyBegin(braceCount == 0 ? previousState: BRACES); + return LBRACE; + } + case 35: break; + case 18: + // general lookahead, find correct zzMarkedPos + { int zzFState = 12; + int zzFPos = zzStartRead; + if (zzFin.length <= (zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())) { zzFin = new boolean[(zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())+1]; } + boolean zzFinL[] = zzFin; + while (zzFState != -1 && zzFPos < zzMarkedPos) { + zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1); + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzFPos++] : zzBufferL.charAt(zzFPos++)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + } + if (zzFState != -1) { zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1); } + while (zzFPos <= zzMarkedPos) { + zzFinL[zzFPos++] = false; + } + + zzFState = 7; + zzFPos = zzMarkedPos; + while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[--zzFPos] : zzBufferL.charAt(--zzFPos)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + }; + zzMarkedPos = zzFPos; + } + { yyBegin(INDENT_VALUE); + valueIndent = currentLineIndent; + valueTokenType = SCALAR_TEXT; + return valueTokenType; + } + case 36: break; + case 16: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; + { return COLON; + } + case 37: break; + case 19: + { return SCALAR_DSTRING; + } + case 38: break; + case 14: + { IElementType type = getWhitespaceTypeAndUpdateIndent(); + if (currentLineIndent <= valueIndent) { + yyBegin(YYINITIAL); + } + return type; + } + case 39: break; + case 11: + { braceCount++; + if (braceCount != 0 && yystate() != BRACES) { + previousState = yystate(); + } + yyBegin(braceCount == 0 ? previousState: BRACES); + return LBRACKET; + } + case 40: break; + case 6: + { // YAML spec: when a comment follows another syntax element, + // it must be separated from it by space characters. + return (isAfterEol() || isAfterSpace()) ? COMMENT : TEXT; + } + case 41: break; + case 8: + { if (braceCount == 0) { + yyBegin(VALUE); + return TEXT; + } + braceCount--; + if (yystate() == BRACES && braceCount == 0){ + yyBegin(previousState); + } + return RBRACKET; + } + case 42: break; + case 22: + // general lookahead, find correct zzMarkedPos + { int zzFState = 13; + int zzFPos = zzStartRead; + if (zzFin.length <= (zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())) { zzFin = new boolean[(zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())+1]; } + boolean zzFinL[] = zzFin; + while (zzFState != -1 && zzFPos < zzMarkedPos) { + zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1); + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzFPos++] : zzBufferL.charAt(zzFPos++)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + } + if (zzFState != -1) { zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1); } + while (zzFPos <= zzMarkedPos) { + zzFinL[zzFPos++] = false; + } + + zzFState = 7; + zzFPos = zzMarkedPos; + while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[--zzFPos] : zzBufferL.charAt(--zzFPos)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + }; + zzMarkedPos = zzFPos; + } + { yyBegin(INDENT_VALUE); + valueIndent = currentLineIndent; + valueTokenType = SCALAR_LIST; + return valueTokenType; + } + case 43: break; + case 17: + // lookahead expression with fixed base length + zzMarkedPos = zzStartRead + 1; + { yyBegin(VALUE_OR_KEY); + return SEQUENCE_MARKER; + } + case 44: break; + case 20: + { return SCALAR_STRING; + } + case 45: break; + case 3: + { return TEXT; + } + case 46: break; + case 24: + // general lookahead, find correct zzMarkedPos + { int zzFState = 10; + int zzFPos = zzStartRead; + if (zzFin.length <= (zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())) { zzFin = new boolean[(zzBufferArrayL != null ? zzBufferArrayL.length : zzBufferL.length())+1]; } + boolean zzFinL[] = zzFin; + while (zzFState != -1 && zzFPos < zzMarkedPos) { + zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1); + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[zzFPos++] : zzBufferL.charAt(zzFPos++)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + } + if (zzFState != -1) { zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1); } + while (zzFPos <= zzMarkedPos) { + zzFinL[zzFPos++] = false; + } + + zzFState = 11; + zzFPos = zzMarkedPos; + while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) { + zzInput = (zzBufferArrayL != null ? zzBufferArrayL[--zzFPos] : zzBufferL.charAt(--zzFPos)); + zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMapL[zzInput] ]; + }; + zzMarkedPos = zzFPos; + } + { yyBegin(VALUE); + return SCALAR_KEY; + } + case 47: break; + case 2: + { if (braceCount == 0) { + yyBegin(YYINITIAL); + } + currentLineIndent = 0; + return EOL; + } + case 48: break; + case 4: + { if (braceCount > 0) { + yyBegin(BRACES); + return COMMA; + } + yyBegin(VALUE); + return TEXT; + } + case 49: break; + case 13: + { currentLineIndent = 0; + return EOL; + } + case 50: break; + case 10: + { if (braceCount == 0) { + yyBegin(VALUE); + return TEXT; + } + braceCount--; + if (yystate() == BRACES && braceCount == 0){ + yyBegin(previousState); + } + return RBRACE; + } + case 51: break; + case 12: + { if (currentLineIndent <= valueIndent) { + yypushback(yylength()); + yyBegin(YYINITIAL); + break; + } else { + return valueTokenType; + } + } + case 52: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + zzDoEOF(); + return null; + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/plugins/yaml/resources/META-INF/plugin.xml b/plugins/yaml/resources/META-INF/plugin.xml new file mode 100644 index 000000000000..935653c6a0c2 --- /dev/null +++ b/plugins/yaml/resources/META-INF/plugin.xml @@ -0,0 +1,32 @@ + + YAML + org.jetbrains.plugins.yaml + JetBrains + YAML support + + com.intellij.modules.lang + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/yaml/resources/messages/YAMLBundle.properties b/plugins/yaml/resources/messages/YAMLBundle.properties new file mode 100644 index 000000000000..d9f67d757886 --- /dev/null +++ b/plugins/yaml/resources/messages/YAMLBundle.properties @@ -0,0 +1,15 @@ +filetype.description.yaml=YAML files + +color.settings.yaml.name=YAML +color.settings.yaml.key=Key +color.settings.yaml.string=String +color.settings.yaml.dstring=Double quoted string +color.settings.yaml.scalar.list='|' block +color.settings.yaml.scalar.text='>' block +color.settings.yaml.text=Text +color.settings.yaml.sign=Sign: brace, comma, etc +color.settings.yaml.comment=Comment + +new.name.conflicts.with=Key conflicts with existing one: ''{0}'' +rename.same.name=Same name +rename.wrong.name=Wrong name diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLBundle.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLBundle.java new file mode 100644 index 000000000000..bc2e52c64fc3 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLBundle.java @@ -0,0 +1,43 @@ +package org.jetbrains.yaml; + +import com.intellij.CommonBundle; +import com.intellij.reference.SoftReference; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.PropertyKey; + +import java.lang.ref.Reference; +import java.util.ResourceBundle; + +/** + * @author oleg + */ +public class YAMLBundle { + + public static String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, @NotNull Object... params) { + return CommonBundle.message(getBundle(), key, params); + } + + private static Reference ourBundle; + @NonNls + private static final String BUNDLE = "messages.YAMLBundle"; + + private YAMLBundle() { + } + + /* + * This method added for jruby access + */ + public static String message(@PropertyKey(resourceBundle = BUNDLE) String key) { + return CommonBundle.message(getBundle(), key); + } + + private static ResourceBundle getBundle() { + ResourceBundle bundle = SoftReference.dereference(ourBundle); + if (bundle == null) { + bundle = ResourceBundle.getBundle(BUNDLE); + ourBundle = new SoftReference(bundle); + } + return bundle; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLCodeStyleSettingsProvider.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLCodeStyleSettingsProvider.java new file mode 100644 index 000000000000..38edabcd488c --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLCodeStyleSettingsProvider.java @@ -0,0 +1,42 @@ +package org.jetbrains.yaml; + +import com.intellij.application.options.CodeStyleAbstractConfigurable; +import com.intellij.application.options.CodeStyleAbstractPanel; +import com.intellij.application.options.TabbedLanguageCodeStylePanel; +import com.intellij.openapi.options.Configurable; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsProvider; +import org.jetbrains.annotations.NotNull; + +/** + * @author oleg + */ +public class YAMLCodeStyleSettingsProvider extends CodeStyleSettingsProvider { + @NotNull + @Override + public Configurable createSettingsPage(final CodeStyleSettings settings, final CodeStyleSettings originalSettings) { + return new CodeStyleAbstractConfigurable(settings, originalSettings, YAMLLanguage.INSTANCE.getDisplayName()) { + @Override + protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) { + final CodeStyleSettings currentSettings = getCurrentSettings(); + final CodeStyleSettings settings1 = settings; + return new TabbedLanguageCodeStylePanel(YAMLLanguage.INSTANCE, currentSettings, settings1) { + @Override + protected void initTabs(final CodeStyleSettings settings) { + addIndentOptionsTab(settings); + } + }; + } + + @Override + public String getHelpTopic() { + return "reference.settingsdialog.codestyle.yaml"; + } + }; + } + + @Override + public String getConfigurableDisplayName() { + return YAMLLanguage.INSTANCE.getDisplayName(); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLColorsPage.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLColorsPage.java new file mode 100644 index 000000000000..30c54292a437 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLColorsPage.java @@ -0,0 +1,86 @@ +package org.jetbrains.yaml; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.options.colors.AttributesDescriptor; +import com.intellij.openapi.options.colors.ColorDescriptor; +import com.intellij.openapi.options.colors.ColorSettingsPage; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.HashMap; +import java.util.Map; + +/** + * @author oleg + */ +public class YAMLColorsPage implements ColorSettingsPage { + + private static final String DEMO_TEXT = "---\n" + + "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\n" + + "static_sidebar:\n" + + " id: \"foo\"\n" + + " name: 'side_bar'\n" + + " staged_position: 1\n" + + " blog_id: 1\n" + + " config: |+\n" + + " --- !map:HashWithIndifferentAccess\n" + + " title: Static Sidebar\n" + + " body: The body of a static sidebar\n" + + " type: StaticSidebar\n" + + " type: > some_type_here"; + + private static final AttributesDescriptor[] ATTRS = new AttributesDescriptor[]{ + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.key"), YAMLHighlighter.SCALAR_KEY), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.string"), YAMLHighlighter.SCALAR_STRING), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.dstring"), YAMLHighlighter.SCALAR_DSTRING), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.scalar.list"), YAMLHighlighter.SCALAR_LIST), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.scalar.text"), YAMLHighlighter.SCALAR_TEXT), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.text"), YAMLHighlighter.TEXT), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.sign"), YAMLHighlighter.SIGN), + new AttributesDescriptor(YAMLBundle.message("color.settings.yaml.comment"), YAMLHighlighter.COMMENT) + }; + + // Empty still + private static final Map ADDITIONAL_HIGHLIGHT_DESCRIPTORS = new HashMap(); + + private static final ColorDescriptor[] COLORS = new ColorDescriptor[0]; + + @Nullable + public Map getAdditionalHighlightingTagToDescriptorMap() { + return ADDITIONAL_HIGHLIGHT_DESCRIPTORS; + } + + @NotNull + public String getDisplayName() { + return YAMLBundle.message("color.settings.yaml.name"); + } + + @NotNull + public Icon getIcon() { + return AllIcons.Nodes.DataTables; + } + + @NotNull + public AttributesDescriptor[] getAttributeDescriptors() { + return ATTRS; + } + + @NotNull + public ColorDescriptor[] getColorDescriptors() { + return COLORS; + } + + @NotNull + public SyntaxHighlighter getHighlighter() { + return new YAMLSyntaxHighlighter(); + } + + @NotNull + public String getDemoText() { + return DEMO_TEXT; + } + +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLCommenter.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLCommenter.java new file mode 100644 index 000000000000..0522ab427d35 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLCommenter.java @@ -0,0 +1,34 @@ +package org.jetbrains.yaml; + +import com.intellij.lang.Commenter; +import org.jetbrains.annotations.NonNls; + +/** + * @author Roman Chernyatchik + */ +public class YAMLCommenter implements Commenter { + @NonNls + private static final String LINE_COMMENT_PREFIX = "#"; + + public String getLineCommentPrefix() { + return LINE_COMMENT_PREFIX; + } + + public String getBlockCommentPrefix() { + // N/A + return null; + } + + public String getBlockCommentSuffix() { + // N/A + return null; + } + + public String getCommentedBlockCommentPrefix() { + return null; + } + + public String getCommentedBlockCommentSuffix() { + return null; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLElementGenerator.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementGenerator.java new file mode 100644 index 000000000000..bd82eeb578d1 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementGenerator.java @@ -0,0 +1,88 @@ +package org.jetbrains.yaml; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.TokenType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.LocalTimeCounter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLKeyValue; + +import java.util.List; + +/** + * @author traff + */ +public class YAMLElementGenerator { + private final Project myProject; + + public YAMLElementGenerator(Project project) { + myProject = project; + } + + public static YAMLElementGenerator getInstance(Project project) { + return ServiceManager.getService(project, YAMLElementGenerator.class); + } + + @NotNull + public static String createChainedKey(@NotNull List keyComponents, int indentAddition) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < keyComponents.size(); ++i) { + if (i > 0) { + sb.append(StringUtil.repeatSymbol(' ', indentAddition + 2 * i)); + } + sb.append(keyComponents.get(i)).append(":"); + if (i + 1 < keyComponents.size()) { + sb.append('\n'); + } + } + return sb.toString(); + } + + @NotNull + public YAMLKeyValue createYamlKeyValue(@NotNull String keyName, @NotNull String valueText) { + final PsiFile tempFile = createDummyYamlWithText(keyName + ": " + valueText); + return PsiTreeUtil.collectElementsOfType(tempFile, YAMLKeyValue.class).iterator().next(); + } + + @NotNull + public YAMLFile createDummyYamlWithText(@NotNull String text) { + return (YAMLFile) PsiFileFactory.getInstance(myProject) + .createFileFromText("temp." + YAMLFileType.YML.getDefaultExtension(), YAMLFileType.YML, text, LocalTimeCounter.currentTime(), true); + } + + @NotNull + public PsiElement createEol() { + final YAMLFile file = createDummyYamlWithText("\n"); + return PsiTreeUtil.getDeepestFirst(file); + } + + @NotNull + public PsiElement createSpace() { + final YAMLKeyValue keyValue = createYamlKeyValue("foo", "bar"); + final ASTNode whitespaceNode = keyValue.getNode().findChildByType(TokenType.WHITE_SPACE); + assert whitespaceNode != null; + return whitespaceNode.getPsi(); + } + + @NotNull + public PsiElement createIndent(int size) { + final YAMLFile file = createDummyYamlWithText(StringUtil.repeatSymbol(' ', size)); + return PsiTreeUtil.getDeepestFirst(file); + } + + @NotNull + public PsiElement createColon() { + final YAMLFile file = createDummyYamlWithText("? foo : bar"); + final PsiElement at = file.findElementAt("? foo ".length()); + assert at != null && at.getNode().getElementType() == YAMLTokenTypes.COLON; + return at; + } + +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLElementType.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementType.java new file mode 100644 index 000000000000..7da5bf14ee9a --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementType.java @@ -0,0 +1,13 @@ +package org.jetbrains.yaml; + +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NonNls; + +/** + * @author oleg + */ +public class YAMLElementType extends IElementType { + public YAMLElementType(@NonNls String debugName) { + super(debugName, YAMLFileType.YML.getLanguage()); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLElementTypes.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementTypes.java new file mode 100644 index 000000000000..143cb3c0d36f --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLElementTypes.java @@ -0,0 +1,35 @@ +package org.jetbrains.yaml; + +import com.intellij.psi.tree.IFileElementType; +import com.intellij.psi.tree.TokenSet; + +/** + * @author oleg + */ +public interface YAMLElementTypes { + IFileElementType FILE = new IFileElementType(YAMLLanguage.INSTANCE); + + YAMLElementType DOCUMENT = new YAMLElementType("Document ---"); + + YAMLElementType KEY_VALUE_PAIR = new YAMLElementType("Key value pair"); + //YAMLElementType VALUE = new YAMLElementType("Value"); + YAMLElementType HASH = new YAMLElementType("Hash"); + YAMLElementType ARRAY = new YAMLElementType("Array"); + YAMLElementType SEQUENCE_ITEM = new YAMLElementType("Sequence item"); + YAMLElementType COMPOUND_VALUE = new YAMLElementType("Compound value"); + YAMLElementType MAPPING = new YAMLElementType("Mapping"); + YAMLElementType SEQUENCE = new YAMLElementType("Sequence"); + YAMLElementType SCALAR_LIST_VALUE = new YAMLElementType("Scalar list value"); + YAMLElementType SCALAR_TEXT_VALUE = new YAMLElementType("Scalar text value"); + YAMLElementType SCALAR_PLAIN_VALUE = new YAMLElementType("Scalar plain style"); + YAMLElementType SCALAR_QUOTED_STRING = new YAMLElementType("Scalar quoted string"); + + TokenSet SCALAR_VALUES = TokenSet.create( + YAMLTokenTypes.SCALAR_TEXT, + YAMLTokenTypes.SCALAR_STRING, + YAMLTokenTypes.SCALAR_DSTRING, + YAMLTokenTypes.SCALAR_LIST, + YAMLTokenTypes.TEXT, + SCALAR_LIST_VALUE + ); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLFileType.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLFileType.java new file mode 100644 index 000000000000..911240de9649 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLFileType.java @@ -0,0 +1,41 @@ +package org.jetbrains.yaml; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.fileTypes.LanguageFileType; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class YAMLFileType extends LanguageFileType { + public static final YAMLFileType YML = new YAMLFileType(); + @NonNls public static final String DEFAULT_EXTENSION = "yml"; + @NonNls private static final String NAME = "YAML"; + @NonNls private static final String DESCRIPTION = YAMLBundle.message("filetype.description.yaml"); + + private YAMLFileType() { + super(YAMLLanguage.INSTANCE); + } + + @NotNull + public String getName() { + return NAME; + } + + @NotNull + public String getDescription() { + return DESCRIPTION; + } + + @NotNull + public String getDefaultExtension() { + return DEFAULT_EXTENSION; + } + + @Nullable + public Icon getIcon() { + return AllIcons.Nodes.DataTables; + } +} + diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLFileTypeLoader.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLFileTypeLoader.java new file mode 100644 index 000000000000..28eb20948116 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLFileTypeLoader.java @@ -0,0 +1,14 @@ +package org.jetbrains.yaml; + +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; + +/** + * @author oleg + */ +public class YAMLFileTypeLoader extends FileTypeFactory { + public void createFileTypes(final @NotNull FileTypeConsumer consumer) { + consumer.consume(YAMLFileType.YML, YAMLFileType.DEFAULT_EXTENSION + ";yaml"); + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLHighlighter.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLHighlighter.java new file mode 100644 index 000000000000..76d650cb3db7 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLHighlighter.java @@ -0,0 +1,56 @@ +package org.jetbrains.yaml; + +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.openapi.editor.HighlighterColors; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import org.jetbrains.annotations.NonNls; + +/** + * @author oleg + */ +public class YAMLHighlighter { + @NonNls + static final String SCALAR_KEY_ID = "YAML_SCALAR_KEY"; + @NonNls + static final String SCALAR_TEXT_ID = "YAML_SCALAR_VALUE"; + @NonNls + static final String SCALAR_STRING_ID = "YAML_SCALAR_STRING"; + @NonNls + static final String SCALAR_DSTRING_ID = "YAML_SCALAR_DSTRING"; + @NonNls + static final String SCALAR_LIST_ID = "YAML_SCALAR_LIST"; + @NonNls + static final String COMMENT_ID = "YAML_COMMENT"; + @NonNls + static final String TEXT_ID = "YAML_TEXT"; + @NonNls + static final String SIGN_ID = "YAML_SIGN"; + + // Text default attrs + public static final TextAttributesKey SCALAR_KEY_DEFAULT_ATTRS = DefaultLanguageHighlighterColors.KEYWORD; + public static final TextAttributesKey COMMENT_DEFAULT_ATTRS = DefaultLanguageHighlighterColors.DOC_COMMENT; + public static final TextAttributesKey SCALAR_TEXT_DEFAULT_ATTRS = HighlighterColors.TEXT; + public static final TextAttributesKey SCALAR_STRING_DEFAULT_ATTRS = DefaultLanguageHighlighterColors.STRING; + public static final TextAttributesKey SCALAR_DSTRING_DEFAULT_ATTRS = DefaultLanguageHighlighterColors.STRING; + public static final TextAttributesKey SCALAR_LIST_DEFAULT_ATTRS = HighlighterColors.TEXT; + public static final TextAttributesKey TEXT_DEFAULT_ATTRS = HighlighterColors.TEXT; + public static final TextAttributesKey SIGN_DEFAULT_ATTRS = DefaultLanguageHighlighterColors.OPERATION_SIGN; + + // text attributes keys + public static final TextAttributesKey SCALAR_KEY = TextAttributesKey + .createTextAttributesKey(SCALAR_KEY_ID, SCALAR_KEY_DEFAULT_ATTRS); + public static final TextAttributesKey SCALAR_TEXT = TextAttributesKey + .createTextAttributesKey(SCALAR_TEXT_ID, SCALAR_TEXT_DEFAULT_ATTRS); + public static final TextAttributesKey SCALAR_STRING = + TextAttributesKey.createTextAttributesKey(SCALAR_STRING_ID, SCALAR_STRING_DEFAULT_ATTRS); + public static final TextAttributesKey SCALAR_DSTRING = + TextAttributesKey.createTextAttributesKey(SCALAR_DSTRING_ID, SCALAR_DSTRING_DEFAULT_ATTRS); + public static final TextAttributesKey SCALAR_LIST = TextAttributesKey + .createTextAttributesKey(SCALAR_LIST_ID, SCALAR_LIST_DEFAULT_ATTRS); + public static final TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey(COMMENT_ID, COMMENT_DEFAULT_ATTRS); + public static final TextAttributesKey TEXT = TextAttributesKey.createTextAttributesKey(TEXT_ID, TEXT_DEFAULT_ATTRS); + public static final TextAttributesKey SIGN = TextAttributesKey.createTextAttributesKey(SIGN_ID, SIGN_DEFAULT_ATTRS); + + private YAMLHighlighter() { + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguage.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguage.java new file mode 100644 index 000000000000..b8ba079e1d88 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguage.java @@ -0,0 +1,21 @@ +package org.jetbrains.yaml; + +import com.intellij.lang.Language; +import org.jetbrains.annotations.NotNull; + +/** + * @author oleg + */ +public class YAMLLanguage extends Language { + public static final YAMLLanguage INSTANCE = new YAMLLanguage(); + + private YAMLLanguage() { + super("yaml"); + } + + @NotNull + @Override + public String getDisplayName() { + return "YAML"; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguageCodeStyleSettingsProvider.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguageCodeStyleSettingsProvider.java new file mode 100644 index 000000000000..6f0361fccdda --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLLanguageCodeStyleSettingsProvider.java @@ -0,0 +1,64 @@ +package org.jetbrains.yaml; + +import com.intellij.application.options.IndentOptionsEditor; +import com.intellij.lang.Language; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author oleg + */ +public class YAMLLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider { + @Override + public CommonCodeStyleSettings getDefaultCommonSettings() { + CommonCodeStyleSettings defaultSettings = new CommonCodeStyleSettings(YAMLLanguage.INSTANCE); + CommonCodeStyleSettings.IndentOptions indentOptions = defaultSettings.initIndentOptions(); + indentOptions.INDENT_SIZE = 2; + indentOptions.USE_TAB_CHARACTER = false; + return defaultSettings; + } + + @Override + public IndentOptionsEditor getIndentOptionsEditor() { + return new YAMLIndentOptionsEditor(); + } + + @NotNull + @Override + public Language getLanguage() { + return YAMLLanguage.INSTANCE; + } + + @Override + public String getCodeSample(@NotNull SettingsType settingsType) { + return "product: \n" + " name: RubyMine\n" + " version: 8\n" + " vendor: JetBrains\n" + " url: \"https://www.jetbrains.com/ruby\""; + } + + private class YAMLIndentOptionsEditor extends IndentOptionsEditor { + + @Override + protected void addComponents() { + addTabOptions(); + // Tabs in YAML are not allowed + myCbUseTab.setEnabled(false); + + myTabSizeField = createIndentTextField(); + myTabSizeLabel = new JLabel(ApplicationBundle.message("editbox.indent.tab.size")); + // Do not add + //add(myTabSizeLabel, myTabSizeField); + + myIndentField = createIndentTextField(); + myIndentLabel = new JLabel(ApplicationBundle.message("editbox.indent.indent")); + add(myIndentLabel, myIndentField); + } + + public void setEnabled(boolean enabled) { + // Do nothing + } + } + +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLPairedBraceMatcher.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLPairedBraceMatcher.java new file mode 100644 index 000000000000..63810c3e137c --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLPairedBraceMatcher.java @@ -0,0 +1,32 @@ +package org.jetbrains.yaml; + +import com.intellij.lang.BracePair; +import com.intellij.lang.PairedBraceMatcher; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author oleg + */ +public class YAMLPairedBraceMatcher implements PairedBraceMatcher, YAMLTokenTypes { + private static final BracePair[] PAIRS = new BracePair[]{ + new BracePair(LBRACE, RBRACE, true), + new BracePair(LBRACKET, RBRACKET, true), + }; + + @NotNull + public BracePair[] getPairs() { + return PAIRS; + } + + public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType iElementType, @Nullable IElementType iElementType1) { + return true; + } + + public int getCodeConstructStart(final PsiFile file, final int openingBraceOffset) { + return openingBraceOffset; + } +} + diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLParserDefinition.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLParserDefinition.java new file mode 100644 index 000000000000..c2443d1cf1ab --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLParserDefinition.java @@ -0,0 +1,104 @@ +package org.jetbrains.yaml; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.ParserDefinition; +import com.intellij.lang.PsiParser; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.project.Project; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.IFileElementType; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.lexer.YAMLFlexLexer; +import org.jetbrains.yaml.parser.YAMLParser; +import org.jetbrains.yaml.psi.impl.*; + +/** + * @author oleg + */ +public class YAMLParserDefinition implements ParserDefinition, YAMLElementTypes { + private static final TokenSet myCommentTokens = TokenSet.create(YAMLTokenTypes.COMMENT); + + @NotNull + public Lexer createLexer(final Project project) { + return new YAMLFlexLexer(); + } + + @Nullable + public PsiParser createParser(final Project project) { + return new YAMLParser(); + } + + public IFileElementType getFileNodeType() { + return FILE; + } + + @NotNull + public TokenSet getWhitespaceTokens() { + return TokenSet.create(YAMLTokenTypes.WHITESPACE); + } + + @NotNull + public TokenSet getCommentTokens() { + return myCommentTokens; + } + + @NotNull + public TokenSet getStringLiteralElements() { + return TokenSet.create(YAMLTokenTypes.SCALAR_STRING, YAMLTokenTypes.SCALAR_DSTRING, YAMLTokenTypes.TEXT); + } + + @NotNull + public PsiElement createElement(final ASTNode node) { + final IElementType type = node.getElementType(); + if (type == DOCUMENT){ + return new YAMLDocumentImpl(node); + } + if (type == KEY_VALUE_PAIR) { + return new YAMLKeyValueImpl(node); + } + if (type == COMPOUND_VALUE) { + return new YAMLCompoundValueImpl(node); + } + if (type == SEQUENCE) { + return new YAMLBlockSequenceImpl(node); + } + if (type == MAPPING) { + return new YAMLBlockMappingImpl(node); + } + if (type == SEQUENCE_ITEM) { + return new YAMLSequenceItemImpl(node); + } + if (type == HASH) { + return new YAMLHashImpl(node); + } + if (type == ARRAY) { + return new YAMLArrayImpl(node); + } + if (type == SCALAR_LIST_VALUE) { + return new YAMLScalarListImpl(node); + } + if (type == SCALAR_TEXT_VALUE) { + return new YAMLScalarTextImpl(node); + } + if (type == SCALAR_PLAIN_VALUE) { + return new YAMLPlainTextImpl(node); + } + if (type == SCALAR_QUOTED_STRING) { + return new YAMLQuotedTextImpl(node); + } + return new YAMLPsiElementImpl(node); + } + + public PsiFile createFile(final FileViewProvider viewProvider) { + return new YAMLFileImpl(viewProvider); + } + + public SpaceRequirements spaceExistanceTypeBetweenTokens(final ASTNode left, final ASTNode right) { + return SpaceRequirements.MAY; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighter.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighter.java new file mode 100644 index 000000000000..eaa65741c468 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2008 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 org.jetbrains.yaml; + +import com.intellij.lexer.Lexer; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.lexer.YAMLFlexLexer; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author: oleg + * @date: Feb 11, 2008 + */ +public class YAMLSyntaxHighlighter extends SyntaxHighlighterBase implements YAMLTokenTypes { + + private static final Map ATTRIBUTES = new HashMap(); + + static { + ATTRIBUTES.put(SCALAR_KEY, YAMLHighlighter.SCALAR_KEY); + ATTRIBUTES.put(SCALAR_STRING, YAMLHighlighter.SCALAR_STRING); + ATTRIBUTES.put(SCALAR_DSTRING, YAMLHighlighter.SCALAR_DSTRING); + ATTRIBUTES.put(SCALAR_TEXT, YAMLHighlighter.SCALAR_TEXT); + ATTRIBUTES.put(SCALAR_LIST, YAMLHighlighter.SCALAR_LIST); + ATTRIBUTES.put(COMMENT, YAMLHighlighter.COMMENT); + ATTRIBUTES.put(TEXT, YAMLHighlighter.TEXT); + ATTRIBUTES.put(LBRACE, YAMLHighlighter.SIGN); + ATTRIBUTES.put(RBRACE, YAMLHighlighter.SIGN); + ATTRIBUTES.put(LBRACKET, YAMLHighlighter.SIGN); + ATTRIBUTES.put(RBRACKET, YAMLHighlighter.SIGN); + ATTRIBUTES.put(COMMA, YAMLHighlighter.SIGN); + ATTRIBUTES.put(QUESTION, YAMLHighlighter.SIGN); + ATTRIBUTES.put(COLON, YAMLHighlighter.SIGN); + ATTRIBUTES.put(DOCUMENT_MARKER, YAMLHighlighter.SIGN); + ATTRIBUTES.put(SEQUENCE_MARKER, YAMLHighlighter.SIGN); + } + + + @NotNull + public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { + return SyntaxHighlighterBase.pack(ATTRIBUTES.get(tokenType)); + } + + @NotNull + public Lexer getHighlightingLexer() { + return new YAMLFlexLexer(); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighterFactory.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighterFactory.java new file mode 100644 index 000000000000..e0b13efc2d10 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLSyntaxHighlighterFactory.java @@ -0,0 +1,17 @@ +package org.jetbrains.yaml; + +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author yole + */ +public class YAMLSyntaxHighlighterFactory extends SyntaxHighlighterFactory { + @NotNull + public SyntaxHighlighter getSyntaxHighlighter(final Project project, final VirtualFile virtualFile) { + return new YAMLSyntaxHighlighter(); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLTokenTypes.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLTokenTypes.java new file mode 100644 index 000000000000..249d5d93c868 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLTokenTypes.java @@ -0,0 +1,34 @@ +package org.jetbrains.yaml; + +/** + * @author: oleg + */ +public interface YAMLTokenTypes { + YAMLElementType COMMENT = new YAMLElementType("comment"); + YAMLElementType WHITESPACE = new YAMLElementType("whitespace"); + YAMLElementType INDENT = new YAMLElementType("indent"); + YAMLElementType EOL = new YAMLElementType("Eol"); + + YAMLElementType LBRACE = new YAMLElementType("{"); + YAMLElementType RBRACE = new YAMLElementType("}"); + YAMLElementType LBRACKET = new YAMLElementType("["); + YAMLElementType RBRACKET = new YAMLElementType("]"); + YAMLElementType COMMA = new YAMLElementType(","); + YAMLElementType COLON = new YAMLElementType(":"); + YAMLElementType QUESTION = new YAMLElementType("?"); + + YAMLElementType DOCUMENT_MARKER = new YAMLElementType("---"); + YAMLElementType DOCUMENT_END = new YAMLElementType("..."); + YAMLElementType SEQUENCE_MARKER = new YAMLElementType("-"); + + YAMLElementType TAG = new YAMLElementType("tag"); + + YAMLElementType SCALAR_KEY = new YAMLElementType("scalar key"); + YAMLElementType TEXT = new YAMLElementType("text"); + + YAMLElementType SCALAR_STRING = new YAMLElementType("scalar string"); + YAMLElementType SCALAR_DSTRING = new YAMLElementType("scalar dstring"); + + YAMLElementType SCALAR_LIST = new YAMLElementType("scalar list"); + YAMLElementType SCALAR_TEXT = new YAMLElementType("scalar text"); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/YAMLUtil.java b/plugins/yaml/src/org/jetbrains/yaml/YAMLUtil.java new file mode 100644 index 000000000000..bac170d6278f --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/YAMLUtil.java @@ -0,0 +1,288 @@ +package org.jetbrains.yaml; + +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.*; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author oleg + */ +public class YAMLUtil { + + @NotNull + public static String getFullKey(final YAMLKeyValue yamlKeyValue) { + final StringBuilder builder = new StringBuilder(); + YAMLKeyValue element = yamlKeyValue; + PsiElement parent; + while (element!=null && + (parent = PsiTreeUtil.getParentOfType(element, YAMLKeyValue.class, YAMLDocument.class)) instanceof YAMLKeyValue){ + if (builder.length()>0){ + builder.insert(0, '.'); + } + builder.insert(0, element.getKeyText()); + element = (YAMLKeyValue) parent; + } + return builder.toString(); + } + + @NotNull + public static Collection getTopLevelKeys(final YAMLFile file) { + final YAMLValue topLevelValue = file.getDocuments().get(0).getTopLevelValue(); + if (topLevelValue instanceof YAMLMapping) { + return ((YAMLMapping)topLevelValue).getKeyValues(); + } + else { + return Collections.emptyList(); + } + } + + @Nullable + public static YAMLKeyValue getQualifiedKeyInFile(final YAMLFile file, List key) { + return getQualifiedKeyInDocument(file.getDocuments().get(0), key); + } + + @Nullable + public static YAMLKeyValue getQualifiedKeyInDocument(@NotNull YAMLDocument document, @NotNull List key) { + assert key.size() != 0; + + YAMLMapping mapping = ObjectUtils.tryCast(document.getTopLevelValue(), YAMLMapping.class); + for (int i = 0; i < key.size(); i++) { + if (mapping == null) { + return null; + } + + final YAMLKeyValue keyValue = mapping.getKeyValueByKey(key.get(i)); + if (keyValue == null || i + 1 == key.size()) { + return keyValue; + } + + mapping = ObjectUtils.tryCast(keyValue.getValue(), YAMLMapping.class); + } + throw new IllegalStateException("Should have returned from the loop"); + } + + @Nullable + public static YAMLKeyValue getQualifiedKeyInFile(final YAMLFile file, String... key) { + return getQualifiedKeyInFile(file, Arrays.asList(key)); + } + + @Nullable + public static YAMLKeyValue findKeyInProbablyMapping(@Nullable YAMLValue node, @NotNull String keyText) { + if (!(node instanceof YAMLMapping)) { + return null; + } + return ((YAMLMapping)node).getKeyValueByKey(keyText); + } + + @Nullable + public static Pair getValue(final YAMLFile file, String... key) { + final YAMLKeyValue record = getQualifiedKeyInFile(file, key); + if (record != null) { + final PsiElement psiValue = record.getValue(); + return Pair.create(psiValue, record.getValueText()); + } + return null; + } + + //public List getAllKeys(final YAMLFile file){ + // return getAllKeys(file, ArrayUtil.EMPTY_STRING_ARRAY); + //} + // + //public List getAllKeys(final YAMLFile file, final String[] key){ + // final YAMLPsiElement record = getQualifiedKeyInFile(file, key); + // if (record == null){ + // return Collections.emptyList(); + // } + // PsiElement psiValue = ((YAMLKeyValue)record).getValue(); + // + // final StringBuilder builder = new StringBuilder(); + // for (String keyPart : key) { + // if (builder.length() != 0){ + // builder.append("."); + // } + // builder.append(keyPart); + // } + // + // final ArrayList list = new ArrayList(); + // + // addKeysRec(builder.toString(), psiValue, list); + // return list; + //} + + //private static void addKeysRec(final String prefix, final PsiElement element, final List list) { + // if (element instanceof YAMLCompoundValue){ + // for (YAMLPsiElement child : ((YAMLCompoundValue)element).getYAMLElements()) { + // addKeysRec(prefix, child, list); + // } + // } + // if (element instanceof YAMLKeyValue){ + // final YAMLKeyValue yamlKeyValue = (YAMLKeyValue)element; + // final PsiElement psiValue = yamlKeyValue.getValue(); + // String key = yamlKeyValue.getKeyText(); + // if (prefix.length() > 0){ + // key = prefix + "." + key; + // } + // if (YAMLUtil.isScalarOrEmptyCompoundValue(psiValue)) { + // list.add(key); + // } else { + // addKeysRec(key, psiValue, list); + // } + // } + //} + + public YAMLKeyValue createI18nRecord(final YAMLFile file, final String key, final String text) { + return createI18nRecord(file, key.split("\\."), text); + } + + @Nullable + public static YAMLKeyValue createI18nRecord(final YAMLFile file, final String[] key, final String text) { + final YAMLDocument root = file.getDocuments().get(0); + assert root != null; + assert key.length > 0; + + YAMLMapping rootMapping = PsiTreeUtil.findChildOfType(root, YAMLMapping.class); + if (rootMapping == null) { + final YAMLFile yamlFile = YAMLElementGenerator.getInstance(file.getProject()).createDummyYamlWithText(key[0] + ":"); + final YAMLMapping mapping = (YAMLMapping) yamlFile.getDocuments().get(0).getTopLevelValue(); + assert mapping != null; + rootMapping = ((YAMLMapping)root.add(mapping)); + } + + YAMLMapping current = rootMapping; + final int keyLength = key.length; + int i; + for (i = 0; i < keyLength; i++) { + final YAMLKeyValue existingRec = current.getKeyValueByKey(key[i]); + if (existingRec != null){ + final YAMLMapping nextMapping = ObjectUtils.tryCast(existingRec.getValue(), YAMLMapping.class); + + if (nextMapping != null) { + current = nextMapping; + continue; + } + } + + // Calc current key indent + + String indent = StringUtil.repeatSymbol(' ', getIndentInThisLine(current)); + + // Generate items + final StringBuilder builder = new StringBuilder(); + builder.append("---"); + for (int j = i; j < keyLength; j++) { + builder.append("\n").append(indent); + builder.append(key[j]).append(":"); + indent += " "; + } + builder.append(" ").append(text); + + // Create dummy mapping + final YAMLFile fileWithKey = YAMLElementGenerator.getInstance(file.getProject()).createDummyYamlWithText(builder.toString()); + final YAMLMapping dummyMapping = PsiTreeUtil.findChildOfType(fileWithKey.getDocuments().get(0), YAMLMapping.class); + assert dummyMapping != null && dummyMapping.getKeyValues().size() == 1; + + // Add or replace + final YAMLKeyValue dummyKeyValue = dummyMapping.getKeyValues().iterator().next(); + current.putKeyValue(dummyKeyValue); + + if (!(dummyKeyValue.getValue() instanceof YAMLMapping)) { + return dummyKeyValue; + } + else { + current = ((YAMLMapping)dummyKeyValue.getValue()); + } + + } + + // Conflict with existing value + final StringBuilder builder = new StringBuilder(); + final int top = Math.min(i + 1, keyLength); + for (int j=0;j 0){ + builder.append('.'); + } + builder.append(key[j]); + } + throw new IncorrectOperationException(YAMLBundle.message("new.name.conflicts.with", builder.toString())); + } + + //public static void removeI18nRecord(final YAMLFile file, final String[] key){ + // PsiElement element = getQualifiedKeyInFile(file, key); + // while (element != null){ + // final PsiElement parent = element.getParent(); + // if (parent instanceof YAMLDocument) { + // ((YAMLKeyValue)element).getValue().delete(); + // return; + // } + // if (parent instanceof YAMLCompoundValue) { + // if (((YAMLCompoundValue)parent).getYAMLElements().size() > 1) { + // element.delete(); + // return; + // } + // } + // element = parent; + // } + //} + + public static PsiElement rename(final YAMLKeyValue element, final String newName) { + if (newName.contains(".")){ + throw new IncorrectOperationException(YAMLBundle.message("rename.wrong.name")); + } + if (newName.equals(element.getName())){ + throw new IncorrectOperationException(YAMLBundle.message("rename.same.name")); + } + final YAMLKeyValue topKeyValue = YAMLElementGenerator.getInstance(element.getProject()).createYamlKeyValue(newName, "Foo"); + + final PsiElement key = element.getKey(); + if (key == null || topKeyValue.getKey() == null) { + throw new IllegalStateException(); + } + key.replace(topKeyValue.getKey()); + return element; + } + + public static int getIndentInThisLine(@NotNull final PsiElement elementInLine) { + PsiElement currentElement = elementInLine; + while (currentElement != null) { + final IElementType type = currentElement.getNode().getElementType(); + if (type == YAMLTokenTypes.EOL) { + return 0; + } + if (type == YAMLTokenTypes.INDENT) { + return currentElement.getTextLength(); + } + + currentElement = PsiTreeUtil.prevLeaf(currentElement); + } + return 0; + } + + public static int getIndentToThisElement(@NotNull final PsiElement element) { + int offset = element.getTextOffset(); + + PsiElement currentElement = element; + while (currentElement != null) { + final IElementType type = currentElement.getNode().getElementType(); + if (type == YAMLTokenTypes.EOL) { + return offset - currentElement.getTextOffset() - 1; + } + + currentElement = PsiTreeUtil.prevLeaf(currentElement); + } + return offset; + } + + +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/completion/YamlKeyCompletionInsertHandler.java b/plugins/yaml/src/org/jetbrains/yaml/completion/YamlKeyCompletionInsertHandler.java new file mode 100644 index 000000000000..543008a8b203 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/completion/YamlKeyCompletionInsertHandler.java @@ -0,0 +1,116 @@ +package org.jetbrains.yaml.completion; + +import com.intellij.codeInsight.completion.InsertHandler; +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorModificationUtil; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLDocument; +import org.jetbrains.yaml.psi.YAMLKeyValue; +import org.jetbrains.yaml.psi.YAMLValue; + +public abstract class YamlKeyCompletionInsertHandler implements InsertHandler { + + @NotNull + protected abstract YAMLKeyValue createNewEntry(@NotNull YAMLDocument document, T item); + + @Override + public void handleInsert(InsertionContext context, T item) { + final PsiElement currentElement = context.getFile().findElementAt(context.getStartOffset()); + assert currentElement != null : "no element at " + context.getStartOffset(); + + final YAMLDocument holdingDocument = PsiTreeUtil.getParentOfType(currentElement, YAMLDocument.class); + assert holdingDocument != null; + + final YAMLValue oldValue = deleteLookupTextAndRetrieveOldValue(context, currentElement); + final YAMLKeyValue created = createNewEntry(holdingDocument, item); + + context.getEditor().getCaretModel().moveToOffset(created.getTextRange().getEndOffset()); + if (oldValue != null) { + WriteCommandAction.runWriteCommandAction(context.getProject(), new Runnable() { + @Override + public void run() { + created.setValue(oldValue); + } + }); + } + + PsiDocumentManager.getInstance(context.getProject()).doPostponedOperationsAndUnblockDocument(context.getDocument()); + + if (!isCharAtCaret(context.getEditor(), ' ')) { + EditorModificationUtil.insertStringAtCaret(context.getEditor(), " "); + } + else { + context.getEditor().getCaretModel().moveCaretRelatively(1, 0, false, false, true); + } + } + + @Nullable + protected YAMLValue deleteLookupTextAndRetrieveOldValue(InsertionContext context, @NotNull PsiElement elementAtCaret) { + final YAMLValue oldValue; + if (elementAtCaret.getNode().getElementType() != YAMLTokenTypes.SCALAR_KEY) { + deleteLookupPlain(context); + return null; + } + + final YAMLKeyValue keyValue = PsiTreeUtil.getParentOfType(elementAtCaret, YAMLKeyValue.class); + assert keyValue != null; + + context.commitDocument(); + if (keyValue.getValue() != null) { + // Save old value somewhere + final YAMLKeyValue dummyKV = YAMLElementGenerator.getInstance(context.getProject()).createYamlKeyValue("foo", "b"); + dummyKV.setValue(keyValue.getValue()); + oldValue = dummyKV.getValue(); + } + else { + oldValue = null; + } + + context.setTailOffset(keyValue.getTextRange().getEndOffset()); + WriteCommandAction.runWriteCommandAction(context.getProject(), new Runnable() { + @Override + public void run() { + keyValue.getParentMapping().deleteKeyValue(keyValue); + } + }); + return oldValue; + } + + private static void deleteLookupPlain(InsertionContext context) { + final Document document = context.getDocument(); + final CharSequence sequence = document.getCharsSequence(); + int offset = context.getStartOffset() - 1; + while (offset >= 0) { + final char c = sequence.charAt(offset); + if (c != ' ' && c != '\t') { + if (c == '\n') { + offset--; + } + else { + offset = context.getStartOffset() - 1; + } + break; + } + offset--; + } + + document.deleteString(offset + 1, context.getTailOffset()); + context.commitDocument(); + } + + public static boolean isCharAtCaret(Editor editor, char ch) { + final int startOffset = editor.getCaretModel().getOffset(); + final Document document = editor.getDocument(); + return document.getTextLength() > startOffset && document.getCharsSequence().charAt(startOffset) == ch; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/folding/YAMLFoldingBuilder.java b/plugins/yaml/src/org/jetbrains/yaml/folding/YAMLFoldingBuilder.java new file mode 100644 index 000000000000..f61a88fd35f7 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/folding/YAMLFoldingBuilder.java @@ -0,0 +1,75 @@ +package org.jetbrains.yaml.folding; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.folding.FoldingBuilder; +import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementTypes; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author oleg + */ +public class YAMLFoldingBuilder implements FoldingBuilder, DumbAware { + + @NotNull + public FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode astNode, @NotNull Document document) { + List descriptors = new LinkedList(); + collectDescriptors(astNode, descriptors); + return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); + } + + private static void collectDescriptors(@NotNull final ASTNode node, @NotNull final List descriptors) { + final IElementType type = node.getElementType(); + final TextRange nodeTextRange = node.getTextRange(); + if (!StringUtil.isEmptyOrSpaces(node.getText()) && nodeTextRange.getLength() >= 2) { + if (type == YAMLElementTypes.KEY_VALUE_PAIR) { + final ASTNode valueNode = node.findChildByType(YAMLElementTypes.COMPOUND_VALUE); + // We should ignore empty compound values + if (valueNode != null && !StringUtil.isEmpty(valueNode.getText().trim())){ + descriptors.add(new FoldingDescriptor(node, nodeTextRange)); + } + } + if (type == YAMLElementTypes.DOCUMENT && + node.getTreeParent().getChildren(TokenSet.create(YAMLElementTypes.DOCUMENT)).length > 1){ + descriptors.add(new FoldingDescriptor(node, nodeTextRange)); + } + if (type == YAMLElementTypes.SCALAR_TEXT_VALUE + || type == YAMLElementTypes.SCALAR_LIST_VALUE + || type == YAMLElementTypes.SCALAR_PLAIN_VALUE) { + descriptors.add(new FoldingDescriptor(node, nodeTextRange)); + } + } + for (ASTNode child : node.getChildren(null)) { + collectDescriptors(child, descriptors); + } + } + + @Nullable + public String getPlaceholderText(@NotNull ASTNode node) { + final IElementType type = node.getElementType(); + if (type == YAMLElementTypes.DOCUMENT){ + return "---"; + } + if (type == YAMLElementTypes.KEY_VALUE_PAIR){ + return node.getFirstChildNode().getText(); + } + if (type == YAMLElementTypes.SCALAR_TEXT_VALUE || type == YAMLElementTypes.SCALAR_LIST_VALUE) { + return node.getText().substring(0, 1); + } + return "..."; + } + + public boolean isCollapsedByDefault(@NotNull ASTNode node) { + return false; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/lexer/YAMLFlexLexer.java b/plugins/yaml/src/org/jetbrains/yaml/lexer/YAMLFlexLexer.java new file mode 100644 index 000000000000..7c0cab0252db --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/lexer/YAMLFlexLexer.java @@ -0,0 +1,61 @@ +package org.jetbrains.yaml.lexer; + +import com.intellij.lexer.FlexAdapter; +import com.intellij.lexer.MergingLexerAdapter; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; + +import java.io.Reader; + +/** + * @author oleg + */ +public class YAMLFlexLexer extends MergingLexerAdapter { + private static final TokenSet TOKENS_TO_MERGE = TokenSet.create(YAMLTokenTypes.TEXT); + + private static final int DIRTY_STATE = 239; + + public YAMLFlexLexer() { + super(new MyFlexAdapter(new _YAMLLexer((Reader) null)), TOKENS_TO_MERGE); + } + + private static class MyFlexAdapter extends FlexAdapter { + + private boolean myStateCleanliness = false; + + public MyFlexAdapter(_YAMLLexer flex) { + super(flex); + } + + @Override + public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { + if (initialState != DIRTY_STATE) { + ((_YAMLLexer)getFlex()).cleanMyState(); + } + else { + // That should not occur normally, but some complex lexers (e.g. black and white lexer) + // require "suspending" of the lexer to pass some template language. In these cases we + // believe that the same instance of the lexer would be restored (with its internal state) + initialState = 0; + } + + super.start(buffer, startOffset, endOffset, initialState); + } + + @Override + public int getState() { + final int state = super.getState(); + if (state != 0 || myStateCleanliness) { + return state; + } + return DIRTY_STATE; + } + + @Override + protected void locateToken() { + myStateCleanliness = ((_YAMLLexer)getFlex()).isCleanState(); + super.locateToken(); + } + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/lexer/yaml.flex b/plugins/yaml/src/org/jetbrains/yaml/lexer/yaml.flex new file mode 100644 index 000000000000..dd5e41534caf --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/lexer/yaml.flex @@ -0,0 +1,391 @@ +package org.jetbrains.yaml.lexer; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.yaml.YAMLTokenTypes; + +/* Auto generated File */ +%% + +%class _YAMLLexer +%implements FlexLexer, YAMLTokenTypes +%unicode +%public + +%function advance +%type IElementType + +%eof{ return; +%eof} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////// USER CODE ////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +%{ + private int currentLineIndent = 0; + private int valueIndent = -1; + private int braceCount = 0; + private IElementType valueTokenType = null; + private int previousState = YYINITIAL; + + public boolean isCleanState() { + return yystate() == YYINITIAL + && currentLineIndent == 0 + && braceCount == 0; + } + + public void cleanMyState() { + currentLineIndent = 0; + braceCount = 0; + } + + private char previousChar() { + return getChar(-1); + } + + private char getChar(final int offset) { + final int loc = getTokenStart() + offset; + return 0 <= loc && loc < zzBuffer.length() ? zzBuffer.charAt(loc) : (char) -1; + } + + private char getCharAfter(final int offset) { + final int loc = getTokenEnd() + offset; + return 0 <= loc && loc < zzBuffer.length() ? zzBuffer.charAt(loc) : (char) -1; + } + + private IElementType getWhitespaceTypeAndUpdateIndent() { + if (isAfterEol()) { + currentLineIndent = yylength(); + return INDENT; + } + else { + return WHITESPACE; + } + } + + private boolean isAfterEol() { + final char prev = previousChar(); + return prev == (char)-1 || prev == '\n'; + } + + private boolean isAfterSpace() { + final char prev = previousChar(); + return prev == (char)-1 || prev == '\t' || prev == ' '; + } + + private void yyBegin(int newState) { + //System.out.println("yybegin(): " + newState); + yybegin(newState); + } + + private boolean startsWith(CharSequence haystack, CharSequence needle) { + for (int i = Math.min(haystack.length(), needle.length()) - 1; i >= 0; i--) { + if (haystack.charAt(i) != needle.charAt(i)) { + return false; + } + } + return true; + } + + private IElementType tokenOrForbidden(IElementType tokenType) { + if (!isAfterEol() || yylength() < 3) { + return tokenType; + } + + if (startsWith(yytext(), "---")) { + braceCount = 0; + yyBegin(YYINITIAL); + yypushback(yylength() - 3); + return DOCUMENT_MARKER; + } + if (startsWith(yytext(), "...")) { + braceCount = 0; + yyBegin(YYINITIAL); + yypushback(yylength() - 3); + return DOCUMENT_END; + } + return tokenType; + } +%} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////// REGEXPS DECLARATIONS ////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// NB !(!a|b) is "a - b" +// From the spec +ANY_CHAR = [^\n] | "\n" + +NS_CHAR = [^\n\t\r\ ] +NS_INDICATOR = [-?:,\[\]\{\}#&*!|>'\"%@`] + +NS_PLAIN_SAFE_flow = [^\n\r\t\ ,\[\]\{\}] // NS_CHAR - flow indicators +NS_PLAIN_SAFE_block = {NS_CHAR} + +NS_PLAIN_FIRST_flow = !(!{NS_CHAR}|{NS_INDICATOR}) | [?:-] {NS_PLAIN_SAFE_flow} +NS_PLAIN_FIRST_block = !(!{NS_CHAR}|{NS_INDICATOR}) | [?:-] {NS_PLAIN_SAFE_block} + +NS_PLAIN_CHAR_flow = {NS_CHAR} "#" | !(!{NS_PLAIN_SAFE_flow}|[:#]) | ":" {NS_PLAIN_SAFE_flow} +NS_PLAIN_CHAR_block = {NS_CHAR} "#" | !(!{NS_PLAIN_SAFE_block}|[:#]) | ":" {NS_PLAIN_SAFE_block} + +NB_NS_PLAIN_IN_LINE_flow = ({WHITE_SPACE_CHAR}* {NS_PLAIN_CHAR_flow})* +NB_NS_PLAIN_IN_LINE_block = ({WHITE_SPACE_CHAR}* {NS_PLAIN_CHAR_block})* + +NS_PLAIN_ONE_LINE_flow = {NS_PLAIN_FIRST_flow} {NB_NS_PLAIN_IN_LINE_flow} +NS_PLAIN_ONE_LINE_block = {NS_PLAIN_FIRST_block} {NB_NS_PLAIN_IN_LINE_block} + +EOL = "\n" +WHITE_SPACE_CHAR = [ \t] +WHITE_SPACE = {WHITE_SPACE_CHAR}+ + +LINE = .* +COMMENT = "#"{LINE} + +ID = [^\n\-\ {}\[\]#][^\n{}\[\]>:#]* + +KEY_flow = {NS_PLAIN_ONE_LINE_flow} {WHITE_SPACE_CHAR}* ":" +KEY_block = {NS_PLAIN_ONE_LINE_block} {WHITE_SPACE_CHAR}* ":" + +INJECTION = ("{{" {ID} "}"{0,2}) | ("%{" [^}\n]* "}"?) + +ESCAPE_SEQUENCE= \\[^\n] +DSTRING_SINGLE_LINE= \"([^\\\"\n]|{ESCAPE_SEQUENCE})*\" +DSTRING= \"([^\\\"]|{ESCAPE_SEQUENCE}|\\\n)*\" +STRING_SINGLE_LINE= '([^'\n]|'')*' +STRING= '([^']|'')*' +NS_HEX_DIGIT = [[:digit:]a-fA-F] +NS_WORD_CHAR = [:digit:] | "-" | [a-zA-Z] +NS_URI_CHAR = "%" {NS_HEX_DIGIT} {NS_HEX_DIGIT} | {NS_WORD_CHAR} | [#;\/?:@&=+$,_.!~*'()\[\]] +C_VERBATIM_TAG = "!" "<" {NS_URI_CHAR}+ ">" +NS_TAG_CHAR = "%" {NS_HEX_DIGIT} {NS_HEX_DIGIT} | {NS_WORD_CHAR} | [#;\/?:@&=+$_.~*'()] +C_TAG_HANDLE = "!" {NS_WORD_CHAR}+ "!" | "!" "!" | "!" +C_NS_SHORTHAND_TAG = {C_TAG_HANDLE} {NS_TAG_CHAR}+ +C_NON_SPECIFIC_TAG = "!" +C_NS_TAG_PROPERTY = {C_VERBATIM_TAG} | {C_NS_SHORTHAND_TAG} | {C_NON_SPECIFIC_TAG} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// STATES DECLARATIONS ////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +%xstate BRACES, VALUE, VALUE_OR_KEY, VALUE_BRACE, INDENT_VALUE + +%% +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////// RULES declarations //////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + { + +{COMMENT} { + // YAML spec: when a comment follows another syntax element, + // it must be separated from it by space characters. + return (isAfterEol() || isAfterSpace()) ? COMMENT : TEXT; + } + +{EOL} { if (braceCount == 0) { + yyBegin(YYINITIAL); + } + currentLineIndent = 0; + return EOL; + } +"[" { braceCount++; + if (braceCount != 0 && yystate() != BRACES) { + previousState = yystate(); + } + yyBegin(braceCount == 0 ? previousState: BRACES); + return LBRACKET; + } +"]" { if (braceCount == 0) { + yyBegin(VALUE); + return TEXT; + } + braceCount--; + if (yystate() == BRACES && braceCount == 0){ + yyBegin(previousState); + } + return RBRACKET; + } + +"," { if (braceCount > 0) { + yyBegin(BRACES); + return COMMA; + } + yyBegin(VALUE); + return TEXT; + } +":" / ({WHITE_SPACE} | {EOL}) { return COLON; } +"?" { return QUESTION; } + +{C_NS_TAG_PROPERTY} / ({WHITE_SPACE} | {EOL}) { + return TAG; +} + +} + + { + + +{STRING_SINGLE_LINE} ":" { + return SCALAR_KEY; +} + +{DSTRING_SINGLE_LINE} ":" { + return SCALAR_KEY; +} + + +} + + { +{KEY_flow} / !(!{ANY_CHAR}|{NS_PLAIN_SAFE_flow}) { + yyBegin(VALUE_BRACE); + return SCALAR_KEY; +} + +} + + { +{KEY_block} / !(!{ANY_CHAR}|{NS_PLAIN_SAFE_block}) { + yyBegin(VALUE); + return SCALAR_KEY; +} +} + + { + +{WHITE_SPACE} { return getWhitespaceTypeAndUpdateIndent(); } + +} + +{ + +"---" | +"..." { + return tokenOrForbidden(TEXT); +} + +"-" / ({WHITE_SPACE} | {EOL}) { yyBegin(VALUE_OR_KEY); + return SEQUENCE_MARKER; } + +} + + +{ + +{STRING} { + return SCALAR_STRING; +} + +{DSTRING} { + return SCALAR_DSTRING; +} + +} + +{ + +">"("-"|"+")? / ({WHITE_SPACE} | {EOL}) { + yyBegin(INDENT_VALUE); + valueIndent = currentLineIndent; + valueTokenType = SCALAR_TEXT; + return valueTokenType; + } + +"|"("-"|"+")? / ({WHITE_SPACE} | {EOL}) + { yyBegin(INDENT_VALUE); + valueIndent = currentLineIndent; + valueTokenType = SCALAR_LIST; + return valueTokenType; + } + +} + + { + {INJECTION}? {NS_PLAIN_ONE_LINE_block} { + return tokenOrForbidden(TEXT); + } +} + + { + {INJECTION}? {NS_PLAIN_ONE_LINE_flow} { + return tokenOrForbidden(TEXT); + } +} + + { +"{" { braceCount++; + if (braceCount != 0 && yystate() != BRACES) { + previousState = yystate(); + } + yyBegin(braceCount == 0 ? previousState: BRACES); + return LBRACE; + } +"}" { if (braceCount == 0) { + yyBegin(VALUE); + return TEXT; + } + braceCount--; + if (yystate() == BRACES && braceCount == 0){ + yyBegin(previousState); + } + return RBRACE; + } +} + +{ +. { return TEXT; } +} + + { +. { + return TEXT; +} +} + + { + +{EOL} { + currentLineIndent = 0; + return EOL; + } + +{WHITE_SPACE} / {EOL} { + return getWhitespaceTypeAndUpdateIndent(); + } +{WHITE_SPACE} { IElementType type = getWhitespaceTypeAndUpdateIndent(); + if (currentLineIndent <= valueIndent) { + yyBegin(YYINITIAL); + } + return type; + } +[^ \n\t] {LINE}? { if (currentLineIndent <= valueIndent) { + yypushback(yylength()); + yyBegin(YYINITIAL); + break; + } else { + return valueTokenType; + } + } +} + +// Rules for matching EOLs + { + +{KEY_flow} { + if (zzMarkedPos == zzEndRead){ + return SCALAR_KEY; + } + yyBegin(VALUE); + return tokenOrForbidden(TEXT); +} + +} + + { +{KEY_block} { + if (zzMarkedPos == zzEndRead){ + return SCALAR_KEY; + } + yyBegin(VALUE); + return tokenOrForbidden(TEXT); +} +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/parser/YAMLParser.java b/plugins/yaml/src/org/jetbrains/yaml/parser/YAMLParser.java new file mode 100644 index 000000000000..9138502fb490 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/parser/YAMLParser.java @@ -0,0 +1,442 @@ +package org.jetbrains.yaml.parser; + +import com.intellij.lang.ASTNode; +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiParser; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; +import com.intellij.util.containers.Stack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementTypes; +import org.jetbrains.yaml.YAMLTokenTypes; + +/** + * @author oleg + */ +public class YAMLParser implements PsiParser, YAMLTokenTypes { + public static final TokenSet HASH_STOP_TOKENS = TokenSet.create(RBRACE, COMMA); + public static final TokenSet ARRAY_STOP_TOKENS = TokenSet.create(RBRACKET, COMMA); + private PsiBuilder myBuilder; + private boolean eolSeen = false; + private int myIndent; + private PsiBuilder.Marker myAfterLastEolMarker; + + private final Stack myStopTokensStack = new Stack(); + + @NotNull + public ASTNode parse(@NotNull final IElementType root, @NotNull final PsiBuilder builder) { + myBuilder = builder; + myStopTokensStack.clear(); + final PsiBuilder.Marker fileMarker = mark(); + parseFile(); + assert myBuilder.eof() : "Not all tokens were passed."; + fileMarker.done(root); + return builder.getTreeBuilt(); + } + + private void parseFile() { + passJunk(); + parseDocument(); + passJunk(); + while (!myBuilder.eof()) { + parseDocument(); + passJunk(); + } + dropEolMarker(); + } + + private void parseDocument() { + final PsiBuilder.Marker marker = mark(); + if (myBuilder.getTokenType() == DOCUMENT_MARKER) { + advanceLexer(); + } + parseBlockNode(0, false); + dropEolMarker(); + marker.done(YAMLElementTypes.DOCUMENT); + } + + private void parseBlockNode(int indent, boolean insideSequence) { + passJunk(); + + final PsiBuilder.Marker marker = mark(); + PsiBuilder.Marker endOfNodeMarker = null; + IElementType nodeType = null; + + + // It looks like tag for a block node should be located on a separate line + if (getTokenType() == YAMLTokenTypes.TAG && myBuilder.lookAhead(1) == YAMLTokenTypes.EOL) { + advanceLexer(); + } + + int numberOfItems = 0; + while (!eof() && (isJunk() || !eolSeen || myIndent + getIndentBonus(insideSequence) >= indent)) { + if (isJunk()) { + advanceLexer(); + continue; + } + + if (!myStopTokensStack.isEmpty() && myStopTokensStack.peek().contains(getTokenType())) { + rollBackToEol(); + break; + } + + numberOfItems++; + final IElementType parsedTokenType = parseSingleStatement(eolSeen ? myIndent : indent); + if (nodeType == null) { + if (parsedTokenType == YAMLElementTypes.SEQUENCE_ITEM) { + nodeType = YAMLElementTypes.SEQUENCE; + } + else if (parsedTokenType == YAMLElementTypes.KEY_VALUE_PAIR) { + nodeType = YAMLElementTypes.MAPPING; + } + else if (numberOfItems > 1) { + nodeType = YAMLElementTypes.COMPOUND_VALUE; + } + } + if (endOfNodeMarker != null) { + endOfNodeMarker.drop(); + } + endOfNodeMarker = mark(); + + } + + if (endOfNodeMarker != null) { + dropEolMarker(); + endOfNodeMarker.rollbackTo(); + } + else { + rollBackToEol(); + } + if (nodeType != null) { + marker.done(nodeType); + } + else { + marker.drop(); + } + } + + /** + * @link {http://www.yaml.org/spec/1.2/spec.html#id2777534} + */ + private int getIndentBonus(final boolean insideSequence) { + if (!insideSequence && getTokenType() == SEQUENCE_MARKER) { + return 1; + } + else { + return 0; + } + } + + private int getShorthandIndentAddition() { + final int offset = myBuilder.getCurrentOffset(); + final IElementType nextToken = myBuilder.lookAhead(1); + if (nextToken != SEQUENCE_MARKER && nextToken != SCALAR_KEY) { + return 1; + } + if (myBuilder.rawLookup(1) == WHITESPACE) { + return myBuilder.rawTokenTypeStart(2) - offset; + } + else { + return 1; + } + } + + @Nullable + private IElementType parseSingleStatement(int indent) { + if (eof()) { + return null; + } + + final PsiBuilder.Marker marker = mark(); + if (getTokenType() == YAMLTokenTypes.TAG) { + advanceLexer(); + } + + final IElementType tokenType = getTokenType(); + final IElementType nodeType; + if (tokenType == LBRACE) { + nodeType = parseHash(); + } + else if (tokenType == LBRACKET) { + nodeType = parseArray(); + } + else if (tokenType == SEQUENCE_MARKER) { + nodeType = parseSequenceItem(indent); + } + else if (tokenType == QUESTION) { + nodeType = parseExplicitKeyValue(indent); + } + else if (tokenType == SCALAR_KEY) { + nodeType = parseScalarKeyValue(indent); + } + else if (YAMLElementTypes.SCALAR_VALUES.contains(getTokenType())) { + nodeType = parseScalarValue(indent); + } + else { + advanceLexer(); + nodeType = null; + } + + if (nodeType != null) { + marker.done(nodeType); + } + else { + marker.drop(); + } + return nodeType; + } + + @Nullable + private IElementType parseScalarValue(int indent) { + final IElementType tokenType = getTokenType(); + assert YAMLElementTypes.SCALAR_VALUES.contains(tokenType) : "Scalar value expected!"; + if (tokenType == SCALAR_LIST || tokenType == SCALAR_TEXT) { + return parseMultiLineScalar(tokenType); + } + else if (tokenType == TEXT) { + return parseMultiLinePlainScalar(indent); + } + else if (tokenType == SCALAR_DSTRING || tokenType == SCALAR_STRING) { + return parseQuotedString(); + } + else { + advanceLexer(); + return null; + } + } + + @NotNull + private IElementType parseQuotedString() { + advanceLexer(); + return YAMLElementTypes.SCALAR_QUOTED_STRING; + } + + @NotNull + private IElementType parseMultiLineScalar(final IElementType tokenType) { + IElementType type = getTokenType(); + while (type == tokenType || type == INDENT || type == EOL) { + advanceLexer(); + type = getTokenType(); + } + rollBackToEol(); + return tokenType == SCALAR_LIST ? YAMLElementTypes.SCALAR_LIST_VALUE : YAMLElementTypes.SCALAR_TEXT_VALUE; + } + + @NotNull + private IElementType parseMultiLinePlainScalar(final int indent) { + PsiBuilder.Marker lastTextEnd = null; + + IElementType type = getTokenType(); + while (type == TEXT || type == INDENT || type == EOL) { + advanceLexer(); + + if (type == TEXT) { + if (lastTextEnd != null && myIndent < indent) { + break; + } + if (lastTextEnd != null) { + lastTextEnd.drop(); + } + lastTextEnd = mark(); + } + type = getTokenType(); + } + + rollBackToEol(); + assert lastTextEnd != null; + lastTextEnd.rollbackTo(); + return YAMLElementTypes.SCALAR_PLAIN_VALUE; + } + + @NotNull + private IElementType parseExplicitKeyValue(int indent) { + assert getTokenType() == QUESTION; + + int indentAddition = getShorthandIndentAddition(); + advanceLexer(); + + if (!myStopTokensStack.isEmpty() && myStopTokensStack.peek() == HASH_STOP_TOKENS // This means we're inside some hash + && getTokenType() == SCALAR_KEY) { + parseScalarKeyValue(indent); + } + else { + myStopTokensStack.add(TokenSet.create(COLON)); + eolSeen = false; + + passJunk(); + + parseBlockNode(indent + indentAddition, false); + + myStopTokensStack.pop(); + + passJunk(); + if (getTokenType() == COLON) { + indentAddition = getShorthandIndentAddition(); + advanceLexer(); + + eolSeen = false; + parseBlockNode(indent + indentAddition, false); + } + } + + return YAMLElementTypes.KEY_VALUE_PAIR; + } + + + @NotNull + private IElementType parseScalarKeyValue(int indent) { + assert getTokenType() == SCALAR_KEY : "Expected scalar key"; + eolSeen = false; + + int indentAddition = getShorthandIndentAddition(); + advanceLexer(); + + final PsiBuilder.Marker rollbackMarker = mark(); + + passJunk(); + if (eolSeen && (eof() || myIndent + getIndentBonus(false) < indent + indentAddition)) { + dropEolMarker(); + rollbackMarker.rollbackTo(); + } + else { + rollbackMarker.drop(); + parseBlockNode(indent + indentAddition, false); + } + + return YAMLElementTypes.KEY_VALUE_PAIR; + } + + @NotNull + private IElementType parseSequenceItem(int indent) { + assert getTokenType() == SEQUENCE_MARKER; + + int indentAddition = getShorthandIndentAddition(); + advanceLexer(); + eolSeen = false; + passJunk(); + + parseBlockNode(indent + indentAddition, true); + rollBackToEol(); + return YAMLElementTypes.SEQUENCE_ITEM; + } + + @NotNull + private IElementType parseHash() { + assert getTokenType() == LBRACE; + advanceLexer(); + myStopTokensStack.add(HASH_STOP_TOKENS); + + while (!eof()) { + if (getTokenType() == RBRACE) { + advanceLexer(); + break; + } + parseSingleStatement(0); + } + + myStopTokensStack.pop(); + dropEolMarker(); + return YAMLElementTypes.HASH; + } + + @NotNull + private IElementType parseArray() { + assert getTokenType() == LBRACKET; + advanceLexer(); + myStopTokensStack.add(ARRAY_STOP_TOKENS); + + while (!eof()) { + if (getTokenType() == RBRACKET) { + advanceLexer(); + break; + } + if (isJunk()) { + advanceLexer(); + continue; + } + + final PsiBuilder.Marker marker = mark(); + final IElementType parsedElement = parseSingleStatement(0); + if (parsedElement != null) { + marker.done(YAMLElementTypes.SEQUENCE_ITEM); + } + else { + marker.error("Sequence item expected"); + } + + if (getTokenType() == YAMLTokenTypes.COMMA) { + advanceLexer(); + } + } + + myStopTokensStack.pop(); + dropEolMarker(); + return YAMLElementTypes.ARRAY; + } + + private boolean eof() { + return myBuilder.eof() || myBuilder.getTokenType() == DOCUMENT_MARKER; + } + + @Nullable + private IElementType getTokenType() { + return eof() ? null : myBuilder.getTokenType(); + } + + private void dropEolMarker() { + if (myAfterLastEolMarker != null) { + myAfterLastEolMarker.drop(); + myAfterLastEolMarker = null; + } + } + + private void rollBackToEol() { + if (eolSeen && myAfterLastEolMarker != null) { + eolSeen = false; + myAfterLastEolMarker.rollbackTo(); + myAfterLastEolMarker = null; + } + } + + private PsiBuilder.Marker mark() { + dropEolMarker(); + return myBuilder.mark(); + } + + private void advanceLexer() { + if (myBuilder.eof()) { + return; + } + final IElementType type = myBuilder.getTokenType(); + eolSeen = eolSeen || type == EOL; + if (type == EOL) { + // Drop and create new eolMarker + myAfterLastEolMarker = mark(); + myIndent = 0; + } + else if (type == INDENT) { + myIndent = getCurrentTokenLength(); + } + else { + // Drop Eol Marker if other token seen + dropEolMarker(); + } + myBuilder.advanceLexer(); + } + + private int getCurrentTokenLength() { + return myBuilder.rawTokenTypeStart(1) - myBuilder.getCurrentOffset(); + } + + private void passJunk() { + while (!eof() && isJunk()) { + advanceLexer(); + } + } + + private boolean isJunk() { + final IElementType type = getTokenType(); + return type == INDENT || type == EOL; + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLCompoundValue.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLCompoundValue.java new file mode 100644 index 000000000000..f8583e35bef4 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLCompoundValue.java @@ -0,0 +1,11 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.NotNull; + +/** + * @author oleg + */ +public interface YAMLCompoundValue extends YAMLValue { + @NotNull + String getTextValue(); +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLDocument.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLDocument.java new file mode 100644 index 000000000000..9d055cb95e11 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLDocument.java @@ -0,0 +1,11 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.Nullable; + +/** + * @author oleg + */ +public interface YAMLDocument extends YAMLPsiElement { + @Nullable + YAMLValue getTopLevelValue(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLFile.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLFile.java new file mode 100644 index 000000000000..3b42860e9c48 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLFile.java @@ -0,0 +1,12 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.psi.PsiFile; + +import java.util.List; + +/** + * @author oleg + */ +public interface YAMLFile extends PsiFile, YAMLPsiElement { + List getDocuments(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLKeyValue.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLKeyValue.java new file mode 100644 index 000000000000..967b74afbc37 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLKeyValue.java @@ -0,0 +1,33 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.pom.PomTarget; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author oleg + */ +public interface YAMLKeyValue extends YAMLPsiElement, PsiNamedElement, PomTarget { + @Contract(pure = true) + @Nullable + PsiElement getKey(); + + @Contract(pure = true) + @NotNull + String getKeyText(); + + @Contract(pure = true) + @Nullable + YAMLValue getValue(); + + @Contract(pure = true) + @NotNull + String getValueText(); + + YAMLMapping getParentMapping(); + + void setValue(@NotNull YAMLValue value); +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLMapping.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLMapping.java new file mode 100644 index 000000000000..1f718056a308 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLMapping.java @@ -0,0 +1,24 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * A collection representing a set of key-value pairs + */ +public interface YAMLMapping extends YAMLCompoundValue { + @NotNull + Collection getKeyValues(); + + @Nullable + YAMLKeyValue getKeyValueByKey(@NotNull String keyText); + + void putKeyValue(@NotNull YAMLKeyValue keyValueToAdd); + + /** + * This one's different from plain deletion in a way that excess newlines/commas are also deleted + */ + void deleteKeyValue(@NotNull YAMLKeyValue keyValueToDelete); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiElement.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiElement.java new file mode 100644 index 000000000000..d1118d4c7845 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiElement.java @@ -0,0 +1,12 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.psi.NavigatablePsiElement; + +import java.util.List; + +/** + * @author oleg + */ +public interface YAMLPsiElement extends NavigatablePsiElement { + List getYAMLElements(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java new file mode 100644 index 000000000000..af27e00d87dd --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java @@ -0,0 +1,53 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.impl.PsiTreeChangeEventImpl; +import com.intellij.psi.impl.PsiTreeChangePreprocessorBase; +import org.jetbrains.annotations.NotNull; + +/** + * @author oleg + */ +final class YAMLPsiManager extends PsiTreeChangePreprocessorBase { + public YAMLPsiManager(@NotNull Project project) { + super(project); + } + + @Override + protected boolean isInsideCodeBlock(PsiElement element) { + if (element instanceof PsiFileSystemItem) { + return false; + } + + if (element == null || element.getParent() == null) { + return true; + } + + while (true) { + if (element instanceof YAMLFile) { + return false; + } + if (element instanceof PsiFile || element instanceof PsiDirectory) { + return true; + } + PsiElement parent = element.getParent(); + if (!(parent instanceof YAMLFile || + parent instanceof YAMLKeyValue || + parent instanceof YAMLCompoundValue || + parent instanceof YAMLDocument)) { + return true; + } + element = parent; + } + } + + @Override + public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { + if (!(event.getFile() instanceof YAMLFile)) return; + super.treeChanged(event); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLQuotedText.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLQuotedText.java new file mode 100644 index 000000000000..f9e4eca3e5f4 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLQuotedText.java @@ -0,0 +1,5 @@ +package org.jetbrains.yaml.psi; + +public interface YAMLQuotedText extends YAMLScalar { + boolean isSingleQuote(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalar.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalar.java new file mode 100644 index 000000000000..32e431e71257 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalar.java @@ -0,0 +1,10 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.NotNull; + +public interface YAMLScalar extends YAMLValue { + @NotNull + String getTextValue(); + + boolean isMultiline(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarList.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarList.java new file mode 100644 index 000000000000..7b87d8e20f5f --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarList.java @@ -0,0 +1,7 @@ +package org.jetbrains.yaml.psi; + +/** + * @author oleg + */ +public interface YAMLScalarList extends YAMLScalar { +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarText.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarText.java new file mode 100644 index 000000000000..920467b4d3c4 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLScalarText.java @@ -0,0 +1,7 @@ +package org.jetbrains.yaml.psi; + +/** + * @author oleg + */ +public interface YAMLScalarText extends YAMLScalar { +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequence.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequence.java new file mode 100644 index 000000000000..d7434f80601b --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequence.java @@ -0,0 +1,13 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * A collection representing a sequence of items + */ +public interface YAMLSequence extends YAMLCompoundValue { + @NotNull + List getItems(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequenceItem.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequenceItem.java new file mode 100644 index 000000000000..6f37dd1da3c1 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLSequenceItem.java @@ -0,0 +1,16 @@ +package org.jetbrains.yaml.psi; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author oleg + */ +public interface YAMLSequenceItem extends YAMLPsiElement { + @Nullable + YAMLValue getValue(); + @NotNull + Collection getKeysValues(); +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLValue.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLValue.java new file mode 100644 index 000000000000..140d06e25ff1 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLValue.java @@ -0,0 +1,9 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +public interface YAMLValue extends YAMLPsiElement { + @Nullable + PsiElement getTag(); +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLArrayImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLArrayImpl.java new file mode 100644 index 000000000000..2a8617a246f6 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLArrayImpl.java @@ -0,0 +1,19 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLSequence; + +/** + * @author oleg + */ +public class YAMLArrayImpl extends YAMLSequenceImpl implements YAMLSequence { + public YAMLArrayImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "YAML array"; + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockMappingImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockMappingImpl.java new file mode 100644 index 000000000000..1a63a918b023 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockMappingImpl.java @@ -0,0 +1,25 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.YAMLUtil; +import org.jetbrains.yaml.psi.YAMLKeyValue; + +public class YAMLBlockMappingImpl extends YAMLMappingImpl { + public YAMLBlockMappingImpl(@NotNull ASTNode node) { + super(node); + } + + @Override + protected void addNewKey(@NotNull YAMLKeyValue key) { + final int indent = YAMLUtil.getIndentToThisElement(this); + + final YAMLElementGenerator generator = YAMLElementGenerator.getInstance(getProject()); + add(generator.createEol()); + if (indent > 0) { + add(generator.createIndent(indent)); + } + add(key); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockScalarImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockScalarImpl.java new file mode 100644 index 000000000000..7056ba340f80 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockScalarImpl.java @@ -0,0 +1,78 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.YAMLUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public abstract class YAMLBlockScalarImpl extends YAMLScalarImpl { + public YAMLBlockScalarImpl(@NotNull ASTNode node) { + super(node); + } + + @NotNull + protected abstract IElementType getContentType(); + + @Override + public boolean isMultiline() { + return true; + } + + @NotNull + @Override + public List getContentRanges() { + final int myStart = getTextOffset(); + final ASTNode node = getNode(); + final List result = new ArrayList(); + + final int indent = locateIndent(); + + final ASTNode firstEol = node.findChildByType(YAMLTokenTypes.EOL); + if (firstEol == null) { + return Collections.emptyList(); + } + + int thisLineStart = firstEol.getStartOffset() + 1; + for (ASTNode child = firstEol.getTreeNext(); child != null; child = child.getTreeNext()) { + if (child.getElementType() == getContentType()) { + assert thisLineStart != -1; + result.add(TextRange.create(thisLineStart, child.getTextRange().getEndOffset()).shiftRight(-myStart)); + thisLineStart = -1; + + if (node.findChildByType(getContentType(), child.getTreeNext()) == null) { + break; + } + } + else if (child.getElementType() == YAMLTokenTypes.INDENT) { + thisLineStart = child.getStartOffset() + Math.min(indent, child.getTextLength()); + } + if (child.getElementType() == YAMLTokenTypes.EOL) { + if (thisLineStart != -1) { + result.add(TextRange.create(thisLineStart, child.getStartOffset()).shiftRight(-myStart)); + } + thisLineStart = child.getStartOffset() + 1; + } + } + + return result; + } + + private int locateIndent() { + int number = 0; + for (ASTNode child = getNode().getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (child.getElementType() == getContentType()) { + number++; + if (number == 2) { + return YAMLUtil.getIndentInThisLine(child.getPsi()); + } + } + } + return 0; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockSequenceImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockSequenceImpl.java new file mode 100644 index 000000000000..3eaabf75cfda --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLBlockSequenceImpl.java @@ -0,0 +1,10 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import org.jetbrains.annotations.NotNull; + +public class YAMLBlockSequenceImpl extends YAMLSequenceImpl { + public YAMLBlockSequenceImpl(@NotNull ASTNode node) { + super(node); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLCompoundValueImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLCompoundValueImpl.java new file mode 100644 index 000000000000..0377c6e38359 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLCompoundValueImpl.java @@ -0,0 +1,38 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLCompoundValue; +import org.jetbrains.yaml.psi.YAMLScalar; + +/** + * @author oleg + */ +public class YAMLCompoundValueImpl extends YAMLValueImpl implements YAMLCompoundValue { + public YAMLCompoundValueImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "YAML compound value"; + } + + @NotNull + @Override + public String getTextValue() { + PsiElement element = getTag() != null ? getTag().getNextSibling() : getFirstChild(); + + while (element != null && !(element instanceof YAMLScalar)) { + element = element.getNextSibling(); + } + + if (element != null) { + return ((YAMLScalar)element).getTextValue(); + } + else { + return ""; + } + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLDocumentImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLDocumentImpl.java new file mode 100644 index 000000000000..bcefe3e5a752 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLDocumentImpl.java @@ -0,0 +1,28 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.YAMLDocument; +import org.jetbrains.yaml.psi.YAMLValue; + +/** + * @author oleg + */ +public class YAMLDocumentImpl extends YAMLPsiElementImpl implements YAMLDocument { + public YAMLDocumentImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "YAML document"; + } + + @Nullable + @Override + public YAMLValue getTopLevelValue() { + return PsiTreeUtil.findChildOfType(this, YAMLValue.class); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLFileImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLFileImpl.java new file mode 100644 index 000000000000..1567d6c0ad73 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLFileImpl.java @@ -0,0 +1,56 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.extapi.psi.PsiFileBase; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLElementTypes; +import org.jetbrains.yaml.YAMLFileType; +import org.jetbrains.yaml.YAMLLanguage; +import org.jetbrains.yaml.psi.YAMLDocument; +import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLPsiElement; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author oleg + */ +public class YAMLFileImpl extends PsiFileBase implements YAMLFile { + public YAMLFileImpl(FileViewProvider viewProvider) { + super(viewProvider, YAMLLanguage.INSTANCE); + } + + @NotNull + public FileType getFileType() { + return YAMLFileType.YML; + } + + @Override + public String toString() { + return "YAML file"; + } + + public List getDocuments() { + final ArrayList result = new ArrayList(); + for (ASTNode node : getNode().getChildren(TokenSet.create(YAMLElementTypes.DOCUMENT))) { + result.add((YAMLDocument) node.getPsi()); + } + return result; + } + + public List getYAMLElements() { + final ArrayList result = new ArrayList(); + for (ASTNode node : getNode().getChildren(null)) { + final PsiElement psi = node.getPsi(); + if (psi instanceof YAMLPsiElement){ + result.add((YAMLPsiElement) psi); + } + } + return result; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLHashImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLHashImpl.java new file mode 100644 index 000000000000..e7784bfe2735 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLHashImpl.java @@ -0,0 +1,44 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLKeyValue; +import org.jetbrains.yaml.psi.YAMLMapping; + +/** + * @author oleg + */ +public class YAMLHashImpl extends YAMLMappingImpl implements YAMLMapping { + public YAMLHashImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + protected void addNewKey(@NotNull YAMLKeyValue key) { + PsiElement anchor = null; + for (PsiElement child = getLastChild(); child != null; child = child.getPrevSibling()) { + final IElementType type = child.getNode().getElementType(); + if (type == YAMLTokenTypes.COMMA || type == YAMLTokenTypes.LBRACE) { + anchor = child; + } + } + + addAfter(key, anchor); + + final YAMLFile dummyFile = YAMLElementGenerator.getInstance(getProject()).createDummyYamlWithText("{,}"); + final PsiElement comma = dummyFile.findElementAt(1); + assert comma != null && comma.getNode().getElementType() == YAMLTokenTypes.COMMA; + + addAfter(comma, key); + } + + @Override + public String toString() { + return "YAML hash"; + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java new file mode 100644 index 000000000000..6c1e0737cc5b --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java @@ -0,0 +1,180 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import com.intellij.util.PlatformIcons; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.YAMLUtil; +import org.jetbrains.yaml.psi.*; + +import javax.swing.*; + +/** + * @author oleg + */ +public class YAMLKeyValueImpl extends YAMLPsiElementImpl implements YAMLKeyValue { + public YAMLKeyValueImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "YAML key value"; + } + + @Nullable + public PsiElement getKey() { + final PsiElement result = findChildByType(YAMLTokenTypes.SCALAR_KEY); + if (result != null) { + return result; + } + if (isExplicit()) { + return findChildByClass(YAMLCompoundValue.class); + } + return null; + } + + @Nullable + @Override + public YAMLMapping getParentMapping() { + return ObjectUtils.tryCast(super.getParent(), YAMLMapping.class); + } + + @Nullable + @Override + public String getName() { + return getKeyText(); + } + + @NotNull + public String getKeyText() { + final PsiElement keyElement = getKey(); + if (keyElement == null) { + return ""; + } + + if (keyElement instanceof YAMLCompoundValue) { + return ((YAMLCompoundValue)keyElement).getTextValue(); + } + + final String text = keyElement.getText(); + return StringUtil.unquoteString(text.substring(0, text.length() - 1)); + } + + @Nullable + public YAMLValue getValue() { + for (PsiElement child = getLastChild(); child != null; child = child.getPrevSibling()) { + if (child instanceof YAMLValue) { + return ((YAMLValue)child); + } + } + return null; + } + + @NotNull + public String getValueText() { + final YAMLValue value = getValue(); + if (value instanceof YAMLScalar){ + return ((YAMLScalar)value).getTextValue(); + } + else if (value instanceof YAMLCompoundValue) { + return ((YAMLCompoundValue)value).getTextValue(); + } + return ""; + } + + + @Override + public void setValue(@NotNull YAMLValue value) { + adjustWhitespaceToContentType(value instanceof YAMLScalar); + + if (getValue() != null) { + getValue().replace(value); + return; + } + + final YAMLElementGenerator generator = YAMLElementGenerator.getInstance(getProject()); + if (isExplicit()) { + if (findChildByType(YAMLTokenTypes.COLON) == null) { + add(generator.createColon()); + add(generator.createSpace()); + add(value); + } + } + else { + add(value); + } + } + + private void adjustWhitespaceToContentType(boolean isScalar) { + assert getKey() != null; + PsiElement key = getKey(); + + if (key.getNextSibling() != null && key.getNextSibling().getNode().getElementType() == YAMLTokenTypes.COLON) { + key = key.getNextSibling(); + } + + while (key.getNextSibling() != null && !(key.getNextSibling() instanceof YAMLValue)) { + key.getNextSibling().delete(); + } + final YAMLElementGenerator generator = YAMLElementGenerator.getInstance(getProject()); + if (isScalar) { + addAfter(generator.createSpace(), key); + } + else { + final int indent = YAMLUtil.getIndentToThisElement(this); + addAfter(generator.createIndent(indent + 2), key); + addAfter(generator.createEol(), key); + } + } + + @Override + public ItemPresentation getPresentation() { + final YAMLFile yamlFile = (YAMLFile)getContainingFile(); + final PsiElement value = getValue(); + return new ItemPresentation() { + public String getPresentableText() { + if (value instanceof YAMLScalar){ + return getValueText(); + } + return getName(); + } + + public String getLocationString() { + return "[" + yamlFile.getName() + "]"; + } + + public Icon getIcon(boolean open) { + return PlatformIcons.PROPERTY_ICON; + } + }; + } + + public PsiElement setName(@NonNls @NotNull String newName) throws IncorrectOperationException { + return YAMLUtil.rename(this, newName); + } + + /** + * Provide reference contributor with given method registerReferenceProviders implementation: + * registrar.registerReferenceProvider(PlatformPatterns.psiElement(YAMLKeyValue.class), ReferenceProvider); + */ + @NotNull + public PsiReference[] getReferences() { + return ReferenceProvidersRegistry.getReferencesFromProviders(this); + } + + private boolean isExplicit() { + final ASTNode child = getNode().getFirstChildNode(); + return child != null && child.getElementType() == YAMLTokenTypes.QUESTION; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLMappingImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLMappingImpl.java new file mode 100644 index 000000000000..287a1d32e679 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLMappingImpl.java @@ -0,0 +1,76 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.YAMLKeyValue; +import org.jetbrains.yaml.psi.YAMLMapping; + +import java.util.Collection; + +public abstract class YAMLMappingImpl extends YAMLCompoundValueImpl implements YAMLMapping { + public YAMLMappingImpl(@NotNull ASTNode node) { + super(node); + } + + @NotNull + @Override + public Collection getKeyValues() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, YAMLKeyValue.class); + } + + @Nullable + @Override + public YAMLKeyValue getKeyValueByKey(@NotNull String keyText) { + for (YAMLKeyValue keyValue : getKeyValues()) { + if (keyText.equals(keyValue.getKeyText())) { + return keyValue; + } + } + return null; + } + + @Override + public void putKeyValue(@NotNull YAMLKeyValue keyValueToAdd) { + final YAMLKeyValue existingKey = getKeyValueByKey(keyValueToAdd.getKeyText()); + if (existingKey == null) { + addNewKey(keyValueToAdd); + } + else { + existingKey.replace(keyValueToAdd); + } + } + + @Override + public void deleteKeyValue(@NotNull YAMLKeyValue keyValueToDelete) { + if (keyValueToDelete.getParent() != this) { + throw new IllegalArgumentException("KeyValue should be the child of this"); + } + + if (keyValueToDelete.getPrevSibling() != null) { + while (keyValueToDelete.getPrevSibling() != null && !(keyValueToDelete.getPrevSibling() instanceof YAMLKeyValue)) { + keyValueToDelete.getPrevSibling().delete(); + } + } + else { + while (keyValueToDelete.getNextSibling() != null && !(keyValueToDelete.getNextSibling() instanceof YAMLKeyValue)) { + keyValueToDelete.getNextSibling().delete(); + } + } + keyValueToDelete.delete(); + } + + protected abstract void addNewKey(@NotNull YAMLKeyValue key); + + @Override + public String toString() { + return "YAML mapping"; + } + + @NotNull + @Override + public String getTextValue() { + return ""; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPlainTextImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPlainTextImpl.java new file mode 100644 index 000000000000..9be2ed88a891 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPlainTextImpl.java @@ -0,0 +1,62 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLScalar; + +import java.util.ArrayList; +import java.util.List; + +public class YAMLPlainTextImpl extends YAMLScalarImpl implements YAMLScalar { + public YAMLPlainTextImpl(@NotNull ASTNode node) { + super(node); + } + + @NotNull + @Override + public List getContentRanges() { + final int myStart = getTextOffset(); + final ASTNode node = getNode(); + final List result = new ArrayList(); + + boolean seenText = false; + for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { + if (child.getElementType() == YAMLTokenTypes.TEXT) { + seenText = true; + result.add(child.getTextRange().shiftRight(-myStart)); + } + else if (child.getElementType() == YAMLTokenTypes.EOL) { + if (!seenText) { + result.add(child.getTextRange().shiftRight(-myStart)); + } + seenText = false; + } + } + + return result; + } + + @NotNull + @Override + protected String getRangesJoiner(@NotNull CharSequence leftString, @NotNull CharSequence rightString) { + if (leftString.equals("\n") || rightString.equals("\n")) { + return ""; + } + else { + return " "; + } + } + + @Override + public String toString() { + return "YAML plain scalar text"; + } + + + @Override + public boolean isMultiline() { + return getNode().findChildByType(YAMLTokenTypes.EOL) != null; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPsiElementImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPsiElementImpl.java new file mode 100644 index 000000000000..918156a3df83 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLPsiElementImpl.java @@ -0,0 +1,35 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLPsiElement; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author oleg + */ +public class YAMLPsiElementImpl extends ASTWrapperPsiElement implements YAMLPsiElement { + public YAMLPsiElementImpl(@NotNull final ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "YAML element"; + } + + public List getYAMLElements() { + final ArrayList result = new ArrayList(); + for (ASTNode node : getNode().getChildren(null)) { + final PsiElement psi = node.getPsi(); + if (psi instanceof YAMLPsiElement){ + result.add((YAMLPsiElement) psi); + } + } + return result; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLQuotedTextImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLQuotedTextImpl.java new file mode 100644 index 000000000000..777b7e1430ae --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLQuotedTextImpl.java @@ -0,0 +1,99 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLQuotedText; + +import java.util.ArrayList; +import java.util.List; + +public class YAMLQuotedTextImpl extends YAMLScalarImpl implements YAMLQuotedText { + private final boolean myIsSingleQuoted; + + public YAMLQuotedTextImpl(@NotNull ASTNode node) { + super(node); + myIsSingleQuoted = getNode().getFirstChildNode().getElementType() == YAMLTokenTypes.SCALAR_STRING; + } + + @NotNull + @Override + public List getContentRanges() { + List result = new ArrayList(); + + final List lines = StringUtil.split(getText(), "\n", true, false); + // First line has opening quote + int cumulativeOffset = 0; + for (int i = 0; i < lines.size(); ++i) { + final String line = lines.get(i); + + int lineStart = 0; + int lineEnd = line.length(); + if (i == 0) { + lineStart++; + } + else { + while (lineStart < line.length() && Character.isWhitespace(line.charAt(lineStart))) { + lineStart++; + } + } + if (i == lines.size() - 1) { + // Last line has closing quote + lineEnd--; + } + else { + while (lineEnd > lineStart && Character.isWhitespace(line.charAt(lineEnd - 1))) { + lineEnd--; + } + } + + result.add(TextRange.create(lineStart, lineEnd).shiftRight(cumulativeOffset)); + cumulativeOffset += line.length() + 1; + } + + return result; + } + + @NotNull + @Override + protected String getRangesJoiner(@NotNull CharSequence leftString, @NotNull CharSequence rightString) { + if (leftString.length() == 0 || !isSingleQuote() && leftString.charAt(leftString.length() - 1) == '\\') { + return "\n"; + } + else if (rightString.length() == 0) { + return ""; + } + else { + return " "; + } + } + + @NotNull + @Override + public String getTextValue() { + final String gluedText = super.getTextValue(); + if (isSingleQuote()) { + return StringUtil.replace(gluedText, "''", "'"); + } + else { + final String trimmedEndEscapes = StringUtil.replace(gluedText, new String[]{"\\\n", "\\ "}, new String[]{"", " "}); + return StringUtil.replaceUnicodeEscapeSequences(trimmedEndEscapes); + } + } + + @Override + public boolean isMultiline() { + return getText().contains("\n"); + } + + public boolean isSingleQuote() { + return myIsSingleQuoted; + } + + @Override + public String toString() { + return "YAML quoted text"; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarElementManipulator.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarElementManipulator.java new file mode 100644 index 000000000000..54051a030917 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarElementManipulator.java @@ -0,0 +1,25 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.AbstractElementManipulator; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLScalar; + +public class YAMLScalarElementManipulator extends AbstractElementManipulator { + + @NotNull + @Override + public TextRange getRangeInElement(@NotNull YAMLScalar element) { + final String content = element.getText(); + final int startOffset = content.startsWith("'") || content.startsWith("\"") ? 1 : 0; + final int endOffset = content.length() > 1 && (content.endsWith("'") || content.endsWith("\"")) ? -1 : 0; + return new TextRange(startOffset, content.length() + endOffset); + } + + @Override + public YAMLScalar handleContentChange(@NotNull YAMLScalar element, @NotNull TextRange range, String newContent) + throws IncorrectOperationException { + return element; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarImpl.java new file mode 100644 index 000000000000..b81742d349c1 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarImpl.java @@ -0,0 +1,58 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLScalar; + +import java.util.List; + +public abstract class YAMLScalarImpl extends YAMLValueImpl implements YAMLScalar { + public YAMLScalarImpl(@NotNull ASTNode node) { + super(node); + } + + @NotNull + public abstract List getContentRanges(); + + @NotNull + protected abstract String getRangesJoiner(@NotNull CharSequence leftString, @NotNull CharSequence rightString); + + @NotNull + @Override + public String getTextValue() { + final String text = getText(); + + + final StringBuilder builder = new StringBuilder(); + CharSequence prevString = null; + boolean isFirst = true; + for (TextRange range : getContentRanges()) { + final CharSequence curString = range.subSequence(text); + + if (!isFirst) { + builder.append(getRangesJoiner(prevString, curString)); + } + else { + isFirst = false; + } + builder.append(curString); + prevString = curString; + } + return builder.toString(); + } + + + @Override + public PsiReference getReference() { + final PsiReference[] references = getReferences(); + return references.length == 1 ? references[0] : null; + } + + @NotNull + public PsiReference[] getReferences() { + return ReferenceProvidersRegistry.getReferencesFromProviders(this); + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarListImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarListImpl.java new file mode 100644 index 000000000000..a54eb586bdbb --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarListImpl.java @@ -0,0 +1,40 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLScalarList; + +/** + * @author oleg + * @see + */ +public class YAMLScalarListImpl extends YAMLBlockScalarImpl implements YAMLScalarList { + public YAMLScalarListImpl(@NotNull final ASTNode node) { + super(node); + } + + @NotNull + @Override + protected IElementType getContentType() { + return YAMLTokenTypes.SCALAR_LIST; + } + + @NotNull + @Override + public String getTextValue() { + return super.getTextValue() + "\n"; + } + + @NotNull + @Override + protected String getRangesJoiner(@NotNull CharSequence leftString, @NotNull CharSequence rightString) { + return "\n"; + } + + @Override + public String toString() { + return "YAML scalar list"; + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarTextImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarTextImpl.java new file mode 100644 index 000000000000..6aaf7e550f8e --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLScalarTextImpl.java @@ -0,0 +1,51 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLScalarText; + +/** + * @author oleg + */ +public class YAMLScalarTextImpl extends YAMLBlockScalarImpl implements YAMLScalarText { + public YAMLScalarTextImpl(@NotNull final ASTNode node) { + super(node); + } + + @NotNull + @Override + protected IElementType getContentType() { + return YAMLTokenTypes.SCALAR_TEXT; + } + + @NotNull + @Override + protected String getRangesJoiner(@NotNull CharSequence leftString, @NotNull CharSequence rightString) { + if (StringUtil.isEmptyOrSpaces(leftString)) { + return "\n"; + } + if (StringUtil.startsWithChar(leftString, ' ') || StringUtil.startsWithChar(leftString, '\t') + || StringUtil.startsWithChar(rightString, ' ') || StringUtil.startsWithChar(rightString, '\t')) { + return "\n"; + } + if (StringUtil.isEmptyOrSpaces(rightString)) { + return ""; + } + return " "; + } + + @NotNull + @Override + public String getTextValue() { + return super.getTextValue() + "\n"; + } + + @Override + public String toString() { + return "YAML scalar text"; + } + +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceImpl.java new file mode 100644 index 000000000000..4270448edf6f --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceImpl.java @@ -0,0 +1,32 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.psi.YAMLSequence; +import org.jetbrains.yaml.psi.YAMLSequenceItem; + +import java.util.List; + +public abstract class YAMLSequenceImpl extends YAMLCompoundValueImpl implements YAMLSequence { + public YAMLSequenceImpl(@NotNull ASTNode node) { + super(node); + } + + @NotNull + @Override + public List getItems() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, YAMLSequenceItem.class); + } + + @NotNull + @Override + public String getTextValue() { + return ""; + } + + @Override + public String toString() { + return "YAML sequence"; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceItemImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceItemImpl.java new file mode 100644 index 000000000000..f4ccc5f4e236 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLSequenceItemImpl.java @@ -0,0 +1,44 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.YAMLKeyValue; +import org.jetbrains.yaml.psi.YAMLMapping; +import org.jetbrains.yaml.psi.YAMLSequenceItem; +import org.jetbrains.yaml.psi.YAMLValue; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author oleg + */ +public class YAMLSequenceItemImpl extends YAMLPsiElementImpl implements YAMLSequenceItem { + public YAMLSequenceItemImpl(@NotNull final ASTNode node) { + super(node); + } + + @Nullable + @Override + public YAMLValue getValue() { + return PsiTreeUtil.findChildOfType(this, YAMLValue.class); + } + + @NotNull + public Collection getKeysValues() { + final YAMLMapping mapping = PsiTreeUtil.findChildOfType(this, YAMLMapping.class); + if (mapping == null) { + return Collections.emptyList(); + } + else { + return mapping.getKeyValues(); + } + } + + @Override + public String toString() { + return "YAML sequence item"; + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLValueImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLValueImpl.java new file mode 100644 index 000000000000..030b85b3027b --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLValueImpl.java @@ -0,0 +1,31 @@ +package org.jetbrains.yaml.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLTokenTypes; +import org.jetbrains.yaml.psi.YAMLValue; + +abstract class YAMLValueImpl extends YAMLPsiElementImpl implements YAMLValue { + public YAMLValueImpl(@NotNull ASTNode node) { + super(node); + } + + @Nullable + @Override + public PsiElement getTag() { + final PsiElement firstChild = getFirstChild(); + if (firstChild.getNode().getElementType() == YAMLTokenTypes.TAG) { + return firstChild; + } + else { + return null; + } + } + + @Override + public String toString() { + return "YAML value"; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewBuilder.java b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewBuilder.java new file mode 100644 index 000000000000..0373ae182c3d --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewBuilder.java @@ -0,0 +1,31 @@ +package org.jetbrains.yaml.structureView; + +import com.intellij.ide.structureView.StructureViewModel; +import com.intellij.ide.structureView.StructureViewModelBase; +import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; +import com.intellij.ide.util.treeView.smartTree.Sorter; +import com.intellij.openapi.editor.Editor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.YAMLDocument; +import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLKeyValue; + +/** + * @author oleg + */ +public class YAMLStructureViewBuilder extends TreeBasedStructureViewBuilder { + private final YAMLFile myPsiFile; + + public YAMLStructureViewBuilder(@NotNull final YAMLFile psiFile) { + myPsiFile = psiFile; + } + + @Override + @NotNull + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new StructureViewModelBase(myPsiFile, editor, new YAMLStructureViewElement(myPsiFile)) + .withSorters(Sorter.ALPHA_SORTER) + .withSuitableClasses(YAMLFile.class, YAMLDocument.class, YAMLKeyValue.class); + } +} \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java new file mode 100644 index 000000000000..ee690a525bbf --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java @@ -0,0 +1,151 @@ +package org.jetbrains.yaml.structureView; + +import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.navigation.ItemPresentation; +import com.intellij.psi.PsiElement; +import com.intellij.util.PlatformIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.psi.*; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author oleg + */ +public class YAMLStructureViewElement implements StructureViewTreeElement { + private final YAMLPsiElement myElement; + + public YAMLStructureViewElement(final YAMLPsiElement element) { + myElement = element; + } + + @NotNull + public StructureViewTreeElement[] getChildren() { + final Collection children; + if (myElement instanceof YAMLFile) { + children = ((YAMLFile)myElement).getDocuments(); + } + else if (myElement instanceof YAMLDocument) { + children = getChildrenForValue(((YAMLDocument)myElement).getTopLevelValue()); + } + else if (myElement instanceof YAMLSequenceItem) { + children = getChildrenForValue(((YAMLSequenceItem)myElement).getValue()); + } + else if (myElement instanceof YAMLKeyValue) { + children = getChildrenForValue(((YAMLKeyValue)myElement).getValue()); + } + else { + children = Collections.emptyList(); + } + + final List structureElements = new ArrayList(); + for (YAMLPsiElement child : children) { + structureElements.add(new YAMLStructureViewElement(child)); + } + return structureElements.toArray(new StructureViewTreeElement[structureElements.size()]); + } + + @NotNull + private static Collection getChildrenForValue(@Nullable YAMLPsiElement element) { + if (element instanceof YAMLMapping) { + return ((YAMLMapping)element).getKeyValues(); + } + if (element instanceof YAMLSequence) { + return ((YAMLSequence)element).getItems(); + } + return Collections.emptyList(); + } + + + + @NotNull + public ItemPresentation getPresentation() { + if (myElement instanceof YAMLKeyValue){ + final YAMLKeyValue kv = (YAMLKeyValue)myElement; + return new ItemPresentation() { + public String getPresentableText() { + return kv.getKeyText(); + } + + public String getLocationString() { + if (kv.getValue() instanceof YAMLScalar) { + return kv.getValueText(); + } + else { + return null; + } + } + + public Icon getIcon(boolean open) { + final PsiElement value = kv.getValue(); + return value instanceof YAMLScalar ? PlatformIcons.PROPERTY_ICON : PlatformIcons.XML_TAG_ICON; + } + }; + } + if (myElement instanceof YAMLDocument){ + return new ItemPresentation() { + public String getPresentableText() { + return "YAML document"; + } + + public String getLocationString() { + return null; + } + + public Icon getIcon(boolean open) { + return PlatformIcons.XML_TAG_ICON; + } + }; + } + if (myElement instanceof YAMLSequenceItem) { + final YAMLSequenceItem item = ((YAMLSequenceItem)myElement); + return new ItemPresentation() { + @Nullable + @Override + public String getPresentableText() { + if (item.getValue() instanceof YAMLScalar) { + return ((YAMLScalar)item.getValue()).getTextValue(); + } + else { + return "Sequence Item"; + } + } + + @Nullable + @Override + public String getLocationString() { + return null; + } + + @Nullable + @Override + public Icon getIcon(boolean unused) { + return item.getValue() instanceof YAMLScalar ? PlatformIcons.PROPERTY_ICON : PlatformIcons.XML_TAG_ICON; + } + }; + } + return myElement.getPresentation(); + } + + public YAMLPsiElement getValue() { + return myElement; + } + + public void navigate(boolean requestFocus) { + myElement.navigate(requestFocus); + } + + public boolean canNavigate() { + return myElement.canNavigate(); + } + + public boolean canNavigateToSource() { + return myElement.canNavigateToSource(); + } +} + diff --git a/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewFactory.java b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewFactory.java new file mode 100644 index 000000000000..776ce0f72d40 --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewFactory.java @@ -0,0 +1,15 @@ +package org.jetbrains.yaml.structureView; + +import com.intellij.ide.structureView.StructureViewBuilder; +import com.intellij.lang.PsiStructureViewFactory; +import com.intellij.psi.PsiFile; +import org.jetbrains.yaml.psi.YAMLFile; + +/** + * @author oleg + */ +public class YAMLStructureViewFactory implements PsiStructureViewFactory { + public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) { + return new YAMLStructureViewBuilder((YAMLFile) psiFile); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/YAMLLexerTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/YAMLLexerTest.java new file mode 100644 index 000000000000..f55135f823e7 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/YAMLLexerTest.java @@ -0,0 +1,209 @@ +package org.jetbrains.yaml.lexer; + +import com.intellij.lexer.Lexer; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.testFramework.LexerTestCase; + +public class YAMLLexerTest extends LexerTestCase { + @Override + protected Lexer createLexer() { + return new YAMLFlexLexer(); + } + + @Override + protected String getDirPath() { + return PluginPathManager.getPluginHomePathRelative("yaml") + "/testSrc/org/jetbrains/yaml/lexer/data"; + } + + public void test2docs() { + doTest(); + } + + public void testColorspage(){ + doTest(); + } + + public void testDocuments(){ + doTest(); + } + + public void testIndentation(){ + doTest(); + } + + public void testMap_between_seq(){ + doTest(); + } + + public void testMap_map(){ + doTest(); + } + + public void testQuoted_scalars(){ + doTest(); + } + + public void testSample_log(){ + doTest(); + } + + public void testSeq_seq(){ + doTest(); + } + + public void testSequence_mappings(){ + doTest(); + } + + public void testWrong_string_highlighting(){ + doTest(); + } + + public void testValue_injection(){ + doTest(); + } + + public void testValue_injection_2(){ + doTest(); + } + + public void testComma(){ + doTest(); + } + + public void testIndex(){ + doTest(); + } + + public void testKeydots(){ + doTest(); + } + + public void testColons74100(){ + doTest(); + } + + public void testOnlyyamlkey(){ + doTest(); + } + + public void testKey_parens(){ + doTest(); + } + + public void testKey_trailing_space(){ + doTest(); + } + + public void testComments(){ + doTest(); + } + + public void testNon_comment() { + doTest(); + } + + public void testNon_comment2() { + doTest(); + } + + public void testKey_with_brackets() { + doTest(); + } + + public void testStrings() { + doTest(); + } + + public void testStringWithTag() { + doTest(); + } + + public void testNested_seqs() { + doTest(); + } + + public void testMultiline_seq() { + doTest(); + } + + public void testClosing_braces_in_value() { + doTest(); + } + + public void testQuoted_keys() { + doTest(); + } + + public void testTyped_scalar_list() { + doTest(); + } + + public void testMultiline_ruby_16796() { + doTest(); + } + + public void testRuby14738() { + doTest(); + } + + public void testRuby14864() throws Throwable { + doTest(); + } + + public void testRuby15402() throws Throwable { + doTest(); + } + + public void testRuby17389() throws Throwable { + doTest(); + } + + public void testEmptyMultiline() throws Throwable { + doTest(); + } + + public void testMultilineDoubleQuotedKey() { + doTest(); + } + + public void testMultilineSingleQuotedKey() { + doTest(); + } + + public void testMultilineDqLiteralWithEscapedNewlines() { + doTest(); + } + + public void testSmallExplicitDocument() { + doTest(); + } + + public void testSmallStream() { + doTest(); + } + + public void testVerbatimTags() { + doTest(); + } + + public void testTagShorthands() { + doTest(); + } + + public void testOnlyScalars() { + doTest(); + } + + public void testOnlyScalarNoDocument() { + doTest(); + } + + public void testSingleQuotedEscapes() { + doTest(); + } + + private void doTest() { + doFileTest("yml"); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.txt new file mode 100644 index 000000000000..f10a5af5f5e9 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.txt @@ -0,0 +1,28 @@ +comment ('# Ranking of 1998 home runs') +Eol ('\n') +--- ('---') +Eol ('\n') +- ('-') +whitespace (' ') +text ('Mark McGwire') +Eol ('\n') +- ('-') +whitespace (' ') +text ('Sammy Sosa') +Eol ('\n') +- ('-') +whitespace (' ') +text ('Ken Griffey') +Eol ('\n') +Eol ('\n') +comment ('# Team ranking') +Eol ('\n') +--- ('---') +Eol ('\n') +- ('-') +whitespace (' ') +text ('Chicago Cubs') +Eol ('\n') +- ('-') +whitespace (' ') +text ('St Louis Cardinals') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.yml new file mode 100644 index 000000000000..bc711d547cdc --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/2docs.yml @@ -0,0 +1,10 @@ +# Ranking of 1998 home runs +--- +- Mark McGwire +- Sammy Sosa +- Ken Griffey + +# Team ranking +--- +- Chicago Cubs +- St Louis Cardinals diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.txt new file mode 100644 index 000000000000..e0fa9cc9f07f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.txt @@ -0,0 +1,7 @@ +scalar key ('pattern:') +whitespace (' ') +text ('/boo/{id}') +Eol ('\n') +scalar key ('pattern:') +whitespace (' ') +text ('/boo/[id]') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.yml new file mode 100644 index 000000000000..e115f0b66309 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/closing_braces_in_value.yml @@ -0,0 +1,2 @@ +pattern: /boo/{id} +pattern: /boo/[id] diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.txt new file mode 100644 index 000000000000..c4c2369e2eb9 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.txt @@ -0,0 +1,12 @@ +scalar key ('server1:') +whitespace (' ') +text ('http://localhost:9876') +Eol ('\n') +scalar key ('server2:') +Eol ('\n') +indent (' ') +text ('http://localhost:8765') +Eol ('\n') +scalar key ('server3:') +whitespace (' ') +text ('test') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.yml new file mode 100644 index 000000000000..86604f0738a3 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colons74100.yml @@ -0,0 +1,4 @@ +server1: http://localhost:9876 +server2: + http://localhost:8765 +server3: test diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.txt new file mode 100644 index 000000000000..ee0f927f4b0e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.txt @@ -0,0 +1,49 @@ +comment ('# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html') +Eol ('\n') +scalar key ('static_sidebar:') +Eol ('\n') +indent (' ') +scalar key ('id:') +whitespace (' ') +scalar dstring ('"foo"') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +scalar string (''side_bar'') +Eol ('\n') +indent (' ') +scalar key ('staged_position:') +whitespace (' ') +text ('1') +Eol ('\n') +indent (' ') +scalar key ('blog_id:') +whitespace (' ') +text ('1') +Eol ('\n') +indent (' ') +scalar key ('config:') +whitespace (' ') +scalar list ('|+') +Eol ('\n') +indent (' ') +scalar list ('--- !map:HashWithIndifferentAccess') +Eol ('\n') +indent (' ') +scalar list ('title: Static Sidebar') +Eol ('\n') +indent (' ') +scalar list ('body: The body of a static sidebar') +Eol ('\n') +indent (' ') +scalar key ('type:') +whitespace (' ') +text ('StaticSidebar') +Eol ('\n') +indent (' ') +scalar key ('type:') +whitespace (' ') +scalar text ('>') +whitespace (' ') +text ('some_type_here') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.yml new file mode 100644 index 000000000000..0ebd0fa829dc --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/colorspage.yml @@ -0,0 +1,12 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +static_sidebar: + id: "foo" + name: 'side_bar' + staged_position: 1 + blog_id: 1 + config: |+ + --- !map:HashWithIndifferentAccess + title: Static Sidebar + body: The body of a static sidebar + type: StaticSidebar + type: > some_type_here diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.txt new file mode 100644 index 000000000000..ccfec8b59ae0 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.txt @@ -0,0 +1,3 @@ +scalar key ('key:') +whitespace (' ') +text ('Hello, how are you?') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.yml new file mode 100644 index 000000000000..8a28c1d21794 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comma.yml @@ -0,0 +1 @@ +key: Hello, how are you? diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.txt new file mode 100644 index 000000000000..d5a533c14c7d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.txt @@ -0,0 +1,24 @@ +scalar key ('en:') +Eol ('\n') +indent (' ') +scalar key ('aaa:') +whitespace (' ') +scalar dstring ('"AAA"') +Eol ('\n') +comment ('# bbb:') +Eol ('\n') +comment ('# ccc: "CCC"') +Eol ('\n') +scalar key ('installation:') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +[ ('[') +] (']') +whitespace (' ') +comment ('# todo: "Not specified"') +Eol ('\n') +text ('en') +whitespace (' ') +comment ('#comment: TODO') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.yml new file mode 100644 index 000000000000..dfd728b3e877 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/comments.yml @@ -0,0 +1,7 @@ +en: + aaa: "AAA" +# bbb: +# ccc: "CCC" +installation: + name: [] # todo: "Not specified" +en #comment: TODO diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.txt new file mode 100644 index 000000000000..e85045f25254 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.txt @@ -0,0 +1,52 @@ +--- ('---') +Eol ('\n') +scalar key ('RubyMine Develoers:') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('yole') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('romeo') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('den') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('oleg') +Eol ('\n') +--- ('---') +Eol ('\n') +scalar key ('RubyMine Versions:') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('1.0') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('1.1') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('1.1.1') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('1.5 EAP') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('1.5') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.yml new file mode 100644 index 000000000000..f88e3b1def32 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/documents.yml @@ -0,0 +1,13 @@ +--- +RubyMine Develoers: + name: yole + name: romeo + name: den + name: oleg +--- +RubyMine Versions: + - 1.0 + - 1.1 + - 1.1.1 + - 1.5 EAP + - 1.5 diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.txt new file mode 100644 index 000000000000..e2d06aae10d6 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.txt @@ -0,0 +1,26 @@ +--- ('---') +Eol ('\n') +scalar key ('foo:') +whitespace (' ') +scalar text ('>') +Eol ('\n') +scalar key ('bar:') +Eol ('\n') +indent (' ') +scalar key ('abc:') +whitespace (' ') +text ('def') +Eol ('\n') +indent (' ') +scalar key ('ghi:') +whitespace (' ') +scalar text ('>') +Eol ('\n') +indent (' ') +scalar key ('jkl:') +whitespace (' ') +text ('mno') +Eol ('\n') +scalar key ('baz:') +whitespace (' ') +text ('qwe') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.yml new file mode 100644 index 000000000000..3c69f024385b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/emptyMultiline.yml @@ -0,0 +1,7 @@ +--- +foo: > +bar: + abc: def + ghi: > + jkl: mno +baz: qwe \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.txt new file mode 100644 index 000000000000..a6ca77e2018a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.txt @@ -0,0 +1,23 @@ +scalar key ('name:') +whitespace (' ') +text ('Mark McGwire') +Eol ('\n') +scalar key ('accomplishment:') +whitespace (' ') +scalar text ('>') +Eol ('\n') +indent (' ') +scalar text ('Mark set a major league') +Eol ('\n') +indent (' ') +scalar text ('home run record in 1998.') +Eol ('\n') +scalar key ('stats:') +whitespace (' ') +scalar list ('|') +Eol ('\n') +indent (' ') +scalar list ('65 Home Runs') +Eol ('\n') +indent (' ') +scalar list ('0.278 Batting Average') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.yml new file mode 100644 index 000000000000..9f66d881c4b9 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/indentation.yml @@ -0,0 +1,7 @@ +name: Mark McGwire +accomplishment: > + Mark set a major league + home run record in 1998. +stats: | + 65 Home Runs + 0.278 Batting Average diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.txt new file mode 100644 index 000000000000..0f179322883b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.txt @@ -0,0 +1,30 @@ +scalar key ('indexes:') +Eol ('\n') +Eol ('\n') +- ('-') +whitespace (' ') +scalar key ('kind:') +whitespace (' ') +text ('MessageIndex') +Eol ('\n') +indent (' ') +scalar key ('properties:') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +scalar key ('name:') +whitespace (' ') +text ('group_name') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +scalar key ('name:') +whitespace (' ') +text ('created_at') +Eol ('\n') +indent (' ') +scalar key ('direction:') +whitespace (' ') +text ('desc') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.yml new file mode 100644 index 000000000000..b4e02e13829c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/index.yml @@ -0,0 +1,7 @@ +indexes: + +- kind: MessageIndex + properties: + - name: group_name + - name: created_at + direction: desc diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.txt new file mode 100644 index 000000000000..4ec3f3b89315 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.txt @@ -0,0 +1 @@ +scalar key ('comment(c):') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.yml new file mode 100644 index 000000000000..40c2881e1075 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_parens.yml @@ -0,0 +1 @@ +comment(c): diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.txt new file mode 100644 index 000000000000..e1d4163a8552 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.txt @@ -0,0 +1 @@ +scalar key ('foo :') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.yml new file mode 100644 index 000000000000..88e132111d39 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_trailing_space.yml @@ -0,0 +1 @@ +foo : diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.txt new file mode 100644 index 000000000000..f17065fa3584 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.txt @@ -0,0 +1,3 @@ +scalar key ('foo[in_brackets]:') +whitespace (' ') +text ('text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.yml new file mode 100644 index 000000000000..d273b2717e0d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/key_with_brackets.yml @@ -0,0 +1 @@ +foo[in_brackets]: text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.txt new file mode 100644 index 000000000000..05d152bf9076 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.txt @@ -0,0 +1,6 @@ +scalar key ('my.testevent.pre:') +Eol ('\n') +indent (' ') +scalar key ('type:') +whitespace (' ') +text ('sfEvent') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.yml new file mode 100644 index 000000000000..fc7d608d39d5 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/keydots.yml @@ -0,0 +1,3 @@ +my.testevent.pre: + type: sfEvent + diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.txt new file mode 100644 index 000000000000..cb9fb714063c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.txt @@ -0,0 +1,45 @@ +? ('?') +whitespace (' ') +- ('-') +whitespace (' ') +text ('Detroit Tigers') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('Chicago cubs') +Eol ('\n') +: (':') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +text ('2001-07-23') +Eol ('\n') +Eol ('\n') +? ('?') +whitespace (' ') +[ ('[') +whitespace (' ') +text ('New York Yankees') +, (',') +Eol ('\n') +indent (' ') +text ('Atlanta Braves') +whitespace (' ') +] (']') +Eol ('\n') +: (':') +whitespace (' ') +[ ('[') +whitespace (' ') +text ('2001-07-02') +, (',') +whitespace (' ') +text ('2001-08-12') +, (',') +Eol ('\n') +indent (' ') +text ('2001-08-14') +whitespace (' ') +] (']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.yml new file mode 100644 index 000000000000..9123ce21348f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_between_seq.yml @@ -0,0 +1,9 @@ +? - Detroit Tigers + - Chicago cubs +: + - 2001-07-23 + +? [ New York Yankees, + Atlanta Braves ] +: [ 2001-07-02, 2001-08-12, + 2001-08-14 ] diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.txt new file mode 100644 index 000000000000..506fc889167f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.txt @@ -0,0 +1,30 @@ +scalar key ('Mark McGwire:') +whitespace (' ') +{ ('{') +scalar key ('hr:') +whitespace (' ') +text ('65') +, (',') +whitespace (' ') +scalar key ('avg:') +whitespace (' ') +text ('0.278') +} ('}') +Eol ('\n') +scalar key ('Sammy Sosa:') +whitespace (' ') +{ ('{') +Eol ('\n') +indent (' ') +scalar key ('hr:') +whitespace (' ') +text ('63') +, (',') +Eol ('\n') +indent (' ') +scalar key ('avg:') +whitespace (' ') +text ('0.288') +Eol ('\n') +indent (' ') +} ('}') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.yml new file mode 100644 index 000000000000..7a957b23a1b2 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/map_map.yml @@ -0,0 +1,5 @@ +Mark McGwire: {hr: 65, avg: 0.278} +Sammy Sosa: { + hr: 63, + avg: 0.288 + } diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.txt new file mode 100644 index 000000000000..3453657868f3 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.txt @@ -0,0 +1,14 @@ +--- ('---') +Eol ('\n') +scalar key ('foo:') +whitespace (' ') +text ('bar') +Eol ('\n') +scalar key ('"baz":') +whitespace (' ') +text ('babaz') +Eol ('\n') +scalar dstring ('"tra\ntata"') +: (':') +whitespace (' ') +text ('is restricted') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.yml new file mode 100644 index 000000000000..6f37f407fe9b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDoubleQuotedKey.yml @@ -0,0 +1,5 @@ +--- +foo: bar +"baz": babaz +"tra +tata": is restricted \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.txt new file mode 100644 index 000000000000..7066a86b7819 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.txt @@ -0,0 +1,3 @@ +scalar key ('somevalue:') +whitespace (' ') +scalar dstring ('"text text skjdfhjksd fjs djfksjdkfksdfkds jf\\n sdkjfhsjkdfhjkshdfjhsdjkfhskjdf"') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.yml new file mode 100644 index 000000000000..a05961b631bd --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineDqLiteralWithEscapedNewlines.yml @@ -0,0 +1,2 @@ +somevalue: "text text skjdfhjksd fjs djfksjdkfksdfkds jf\ + sdkjfhsjkdfhjkshdfjhsdjkfhskjdf" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.txt new file mode 100644 index 000000000000..821fa13b98e7 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.txt @@ -0,0 +1,14 @@ +--- ('---') +Eol ('\n') +scalar key ('foo:') +whitespace (' ') +text ('bar') +Eol ('\n') +scalar key (''asd':') +whitespace (' ') +text ('def') +Eol ('\n') +scalar string (''dsad\nasd'') +: (':') +whitespace (' ') +text ('restricted') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.yml new file mode 100644 index 000000000000..96dc6f92300f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multilineSingleQuotedKey.yml @@ -0,0 +1,5 @@ +--- +foo: bar +'asd': def +'dsad +asd': restricted \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.txt new file mode 100644 index 000000000000..1b84809e6bcf --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.txt @@ -0,0 +1,23 @@ +scalar key ('copy:') +Eol ('\n') +indent (' ') +text ('src="keys/{{ item }}"') +Eol ('\n') +indent (' ') +text ('dest="{{ deploy_home }}/.ssh/"') +Eol ('\n') +indent (' ') +text ('owner="{{ deploy_user }}"') +Eol ('\n') +indent (' ') +text ('group="{{ deploy_group }}"') +Eol ('\n') +indent (' ') +text ('mode=0600') +Eol ('\n') +scalar key ('with_items:') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +scalar dstring ('"id_rsa"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.yml new file mode 100644 index 000000000000..7abbe02aaa92 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_ruby_16796.yml @@ -0,0 +1,8 @@ +copy: + src="keys/{{ item }}" + dest="{{ deploy_home }}/.ssh/" + owner="{{ deploy_user }}" + group="{{ deploy_group }}" + mode=0600 +with_items: + - "id_rsa" diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.txt new file mode 100644 index 000000000000..c46fe230f869 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.txt @@ -0,0 +1,27 @@ +scalar key ('item:') +Eol ('\n') +- ('-') +Eol ('\n') +indent (' ') +scalar key ('property:') +whitespace (' ') +[ ('[') +Eol ('\n') +indent (' ') +scalar string (''value[]'') +Eol ('\n') +indent (' ') +] (']') +Eol ('\n') +- ('-') +Eol ('\n') +indent (' ') +scalar key ('property:') +whitespace (' ') +[ ('[') +Eol ('\n') +indent (' ') +scalar string (''value'') +Eol ('\n') +indent (' ') +] (']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.yml new file mode 100644 index 000000000000..2378de00cb8f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/multiline_seq.yml @@ -0,0 +1,9 @@ +item: +- + property: [ + 'value[]' + ] +- + property: [ + 'value' + ] \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.txt new file mode 100644 index 000000000000..1a9df5a6650f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.txt @@ -0,0 +1,16 @@ +- ('-') +whitespace (' ') +[ ('[') +whitespace (' ') +text ('setEntityClass') +, (',') +whitespace (' ') +[ ('[') +text ('MyprojectMyBundle:MyEntity') +] (']') +whitespace (' ') +] (']') +Eol ('\n') +- ('-') +whitespace (' ') +text ('something, with comma') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.yml new file mode 100644 index 000000000000..bf16cdbc2602 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/nested_seqs.yml @@ -0,0 +1,2 @@ +- [ setEntityClass, [MyprojectMyBundle:MyEntity] ] +- something, with comma diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.txt new file mode 100644 index 000000000000..f0c8340e38ff --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.txt @@ -0,0 +1,3 @@ +scalar key ('hello:') +whitespace (' ') +text ('hello#my_non_comment') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.yml new file mode 100644 index 000000000000..d70f00094160 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment.yml @@ -0,0 +1 @@ +hello: hello#my_non_comment diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.txt new file mode 100644 index 000000000000..32de8b50f64d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.txt @@ -0,0 +1,3 @@ +scalar key ('foo#non_comment:') +whitespace (' ') +text ('text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.yml new file mode 100644 index 000000000000..c53dbc24f318 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/non_comment2.yml @@ -0,0 +1 @@ +foo#non_comment: text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.txt new file mode 100644 index 000000000000..5500c75a34c8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.txt @@ -0,0 +1,10 @@ +scalar list ('|') +Eol ('\n') +indent (' ') +Eol ('\n') +Eol ('\n') +indent (' ') +scalar list ('foo') +Eol ('\n') +indent (' ') +scalar list ('bar') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.yml new file mode 100644 index 000000000000..b709b46187db --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalarNoDocument.yml @@ -0,0 +1,5 @@ +| + + + foo + bar diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.txt new file mode 100644 index 000000000000..3ca18d10fae0 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.txt @@ -0,0 +1,20 @@ +--- ('---') +whitespace (' ') +scalar list ('|') +Eol ('\n') +indent (' ') +scalar list ('literal') +Eol ('\n') +indent (' ') +scalar list ('text') +Eol ('\n') +Eol ('\n') +--- ('---') +whitespace (' ') +scalar text ('>') +Eol ('\n') +indent (' ') +scalar text ('literal') +Eol ('\n') +indent (' ') +scalar text ('text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.yml new file mode 100644 index 000000000000..8f56ae447637 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyScalars.yml @@ -0,0 +1,7 @@ +--- | + literal + text + +--- > + literal + text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.txt new file mode 100644 index 000000000000..4695702e4dd8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.txt @@ -0,0 +1 @@ +scalar key ('foo:') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.yml new file mode 100644 index 000000000000..0152a79652d9 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/onlyyamlkey.yml @@ -0,0 +1 @@ +foo: diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.txt new file mode 100644 index 000000000000..1a1a07d9e8ba --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.txt @@ -0,0 +1,26 @@ +scalar key ('"quoted key 1":') +whitespace (' ') +[ ('[') +scalar dstring ('"loginGuard"') +, (',') +whitespace (' ') +scalar dstring ('"arrangementPage"') +] (']') +Eol ('\n') +scalar key ('"quoted key 2":') +whitespace (' ') +[ ('[') +scalar dstring ('"loginGuard"') +, (',') +whitespace (' ') +scalar dstring ('"repositoryPage"') +] (']') +Eol ('\n') +scalar key ('key:') +whitespace (' ') +[ ('[') +whitespace (' ') +scalar key ('"quoted key 3":') +whitespace (' ') +scalar dstring ('"loginGuard"') +] (']') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.yml new file mode 100644 index 000000000000..3919af121d9a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_keys.yml @@ -0,0 +1,3 @@ +"quoted key 1": ["loginGuard", "arrangementPage"] +"quoted key 2": ["loginGuard", "repositoryPage"] +key: [ "quoted key 3": "loginGuard"] diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.txt new file mode 100644 index 000000000000..41615970eda3 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.txt @@ -0,0 +1,41 @@ +scalar key ('unicode:') +whitespace (' ') +scalar dstring ('"Sosa did fine.\u263A"') +Eol ('\n') +scalar key ('control:') +whitespace (' ') +scalar dstring ('"\b1998\t1999\t2000\n"') +Eol ('\n') +scalar key ('hex esc:') +whitespace (' ') +scalar dstring ('"\x0d\x0a is \r\n"') +Eol ('\n') +Eol ('\n') +scalar key ('single:') +whitespace (' ') +scalar string (''"Howdy!" he cried.'') +Eol ('\n') +scalar key ('quoted:') +whitespace (' ') +scalar string ('' # not a ''comment''.'') +Eol ('\n') +scalar key ('tie-fighter:') +whitespace (' ') +scalar string (''|\-*-/|'') +Eol ('\n') +scalar key ('foo:') +whitespace (' ') +[ ('[') +scalar string (''a'') +, (',') +whitespace (' ') +scalar string (''b'') +] (']') +Eol ('\n') +scalar key ('key:') +whitespace (' ') +scalar string (''value\'') +Eol ('\n') +scalar key ('key2:') +whitespace (' ') +scalar string (''value'') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.yml new file mode 100644 index 000000000000..6f1e8aa66371 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/quoted_scalars.yml @@ -0,0 +1,10 @@ +unicode: "Sosa did fine.\u263A" +control: "\b1998\t1999\t2000\n" +hex esc: "\x0d\x0a is \r\n" + +single: '"Howdy!" he cried.' +quoted: ' # not a ''comment''.' +tie-fighter: '|\-*-/|' +foo: ['a', 'b'] +key: 'value\' +key2: 'value' diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.txt new file mode 100644 index 000000000000..c8aadaec22f2 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.txt @@ -0,0 +1,16 @@ +scalar key ('my_service:') +Eol ('\n') +indent (' ') +scalar key ('class:') +whitespace (' ') +text ('My\Service') +Eol ('\n') +indent (' ') +scalar key ('arguments:') +whitespace (' ') +[ ('[') +text ('@doctrine.orm.entity_manager') +, (',') +whitespace (' ') +text ('@?logger') +] (']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.yml new file mode 100644 index 000000000000..920fbf3bf301 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14738.yml @@ -0,0 +1,3 @@ +my_service: + class: My\Service + arguments: [@doctrine.orm.entity_manager, @?logger] \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.txt new file mode 100644 index 000000000000..cac55a45f994 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.txt @@ -0,0 +1,10 @@ +scalar key ('a:') +whitespace (' ') +scalar text ('>-') +Eol ('\n') +indent (' ') +scalar text ('aaaaa'sdasdasd') +Eol ('\n') +scalar key ('b:') +whitespace (' ') +text ('1') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.yml new file mode 100644 index 000000000000..70f28f039706 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby14864.yml @@ -0,0 +1,3 @@ +a: >- + aaaaa'sdasdasd +b: 1 \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.txt new file mode 100644 index 000000000000..17e7fc583002 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.txt @@ -0,0 +1,22 @@ +scalar key ('MetalProductsBundle:Products:searchSuggest:') +Eol ('\n') +indent (' ') +scalar key ('path:') +whitespace (' ') +text ('/search-suggest/') +Eol ('\n') +indent (' ') +scalar key ('host:') +whitespace (' ') +scalar dstring ('"{subdomain}.%base_host%"') +Eol ('\n') +indent (' ') +scalar key ('defaults:') +whitespace (' ') +{ ('{') +whitespace (' ') +scalar key ('_controller:') +whitespace (' ') +text ('MetalProductsBundle:Products:searchSuggest') +whitespace (' ') +} ('}') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.yml new file mode 100644 index 000000000000..95d2fb8b07a1 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby15402.yml @@ -0,0 +1,4 @@ +MetalProductsBundle:Products:searchSuggest: + path: /search-suggest/ + host: "{subdomain}.%base_host%" + defaults: { _controller: MetalProductsBundle:Products:searchSuggest } \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.txt new file mode 100644 index 000000000000..57b880fed239 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.txt @@ -0,0 +1,10 @@ +--- ('---') +Eol ('\n') +scalar key ('foo:') +whitespace (' ') +{ ('{') +} ('}') +Eol ('\n') +scalar key ('bar:') +whitespace (' ') +scalar dstring ('"baz"') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.yml new file mode 100644 index 000000000000..588395fbdd07 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/ruby17389.yml @@ -0,0 +1,3 @@ +--- +foo: {} +bar: "baz" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.txt new file mode 100644 index 000000000000..a8455850a24c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.txt @@ -0,0 +1,45 @@ +scalar key ('Date:') +whitespace (' ') +text ('2001-11-23') +Eol ('\n') +scalar key ('Stack:') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +scalar key ('file:') +whitespace (' ') +text ('TopClass.py') +Eol ('\n') +indent (' ') +scalar key ('line:') +whitespace (' ') +text ('23') +Eol ('\n') +indent (' ') +scalar key ('code:') +whitespace (' ') +scalar list ('|') +Eol ('\n') +indent (' ') +scalar list ('x = MoreObject("345\n")') +Eol ('\n') +indent (' ') +- ('-') +whitespace (' ') +scalar key ('file:') +whitespace (' ') +text ('MoreClass.py') +Eol ('\n') +indent (' ') +scalar key ('line:') +whitespace (' ') +text ('58') +Eol ('\n') +indent (' ') +scalar key ('code:') +whitespace (' ') +scalar list ('|-') +Eol ('\n') +indent (' ') +scalar list ('foo = bar') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.yml new file mode 100644 index 000000000000..0eabd448012b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sample_log.yml @@ -0,0 +1,10 @@ +Date: 2001-11-23 +Stack: + - file: TopClass.py + line: 23 + code: | + x = MoreObject("345\n") + - file: MoreClass.py + line: 58 + code: |- + foo = bar diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.txt new file mode 100644 index 000000000000..d0363d128658 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.txt @@ -0,0 +1,38 @@ +- ('-') +whitespace (' ') +[ ('[') +text ('name') +whitespace (' ') +, (',') +whitespace (' ') +text ('hr') +, (',') +whitespace (' ') +text ('avg') +whitespace (' ') +] (']') +Eol ('\n') +- ('-') +whitespace (' ') +[ ('[') +text ('Mark McGwire') +, (',') +whitespace (' ') +text ('65') +, (',') +whitespace (' ') +text ('0.278') +] (']') +Eol ('\n') +- ('-') +whitespace (' ') +[ ('[') +text ('Sammy Sosa') +whitespace (' ') +, (',') +whitespace (' ') +text ('63') +, (',') +whitespace (' ') +text ('0.288') +] (']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.yml new file mode 100644 index 000000000000..cdd7770628b1 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/seq_seq.yml @@ -0,0 +1,3 @@ +- [name , hr, avg ] +- [Mark McGwire, 65, 0.278] +- [Sammy Sosa , 63, 0.288] diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.txt new file mode 100644 index 000000000000..dccd579523e1 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.txt @@ -0,0 +1,33 @@ +- ('-') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('Mark McGwire') +Eol ('\n') +indent (' ') +scalar key ('hr:') +whitespace (' ') +text ('65') +Eol ('\n') +indent (' ') +scalar key ('avg:') +whitespace (' ') +text ('0.278') +Eol ('\n') +- ('-') +Eol ('\n') +indent (' ') +scalar key ('name:') +whitespace (' ') +text ('Sammy Sosa') +Eol ('\n') +indent (' ') +scalar key ('hr:') +whitespace (' ') +text ('63') +Eol ('\n') +indent (' ') +scalar key ('avg:') +whitespace (' ') +text ('0.288') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.yml new file mode 100644 index 000000000000..430f6b3dbe1b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/sequence_mappings.yml @@ -0,0 +1,8 @@ +- + name: Mark McGwire + hr: 65 + avg: 0.278 +- + name: Sammy Sosa + hr: 63 + avg: 0.288 diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.txt new file mode 100644 index 000000000000..e03749b4eb4e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.txt @@ -0,0 +1 @@ +scalar string (''here''s to "quotes"'') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.yml new file mode 100644 index 000000000000..c4b4ca9a0806 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/singleQuotedEscapes.yml @@ -0,0 +1 @@ +'here''s to "quotes"' \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.txt new file mode 100644 index 000000000000..1cce2ed97851 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.txt @@ -0,0 +1,9 @@ +text ('%YAML 1.2') +Eol ('\n') +--- ('---') +Eol ('\n') +text ('Document') +Eol ('\n') +... ('...') +whitespace (' ') +comment ('# Suffix') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.yml new file mode 100644 index 000000000000..bbbc37bdd077 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallExplicitDocument.yml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +Document +... # Suffix \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.txt new file mode 100644 index 000000000000..83f364e4ede8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.txt @@ -0,0 +1,15 @@ +text ('Document') +Eol ('\n') +--- ('---') +Eol ('\n') +comment ('# Empty') +Eol ('\n') +... ('...') +Eol ('\n') +text ('%YAML 1.2') +Eol ('\n') +--- ('---') +Eol ('\n') +scalar key ('matches %:') +whitespace (' ') +text ('20') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.yml new file mode 100644 index 000000000000..4c004fda4ec5 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/smallStream.yml @@ -0,0 +1,7 @@ +Document +--- +# Empty +... +%YAML 1.2 +--- +matches %: 20 \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.txt new file mode 100644 index 000000000000..ab03026398e8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.txt @@ -0,0 +1,5 @@ +scalar key ('foo:') +whitespace (' ') +tag ('!') +whitespace (' ') +scalar dstring ('"tratata"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.yml new file mode 100644 index 000000000000..51045102696e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/stringWithTag.yml @@ -0,0 +1 @@ +foo: ! "tratata" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.txt new file mode 100644 index 000000000000..d3585ab5698f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.txt @@ -0,0 +1,125 @@ +scalar key ('foo1:') +whitespace (' ') +[ ('[') +scalar dstring ('"day"') +, (',') +whitespace (' ') +scalar dstring ('"month"') +, (',') +whitespace (' ') +scalar dstring ('"year"') +] (']') +Eol ('\n') +scalar key ('foo2:') +whitespace (' ') +[ ('[') +scalar string (''day'') +, (',') +whitespace (' ') +scalar string (''month'') +, (',') +whitespace (' ') +scalar string (''year'') +] (']') +Eol ('\n') +scalar key ('foo3:') +whitespace (' ') +[ ('[') +scalar dstring ('"day[1]"') +, (',') +whitespace (' ') +scalar dstring ('"month[1]"') +, (',') +whitespace (' ') +scalar dstring ('"year[1]"') +] (']') +Eol ('\n') +scalar key ('foo4:') +whitespace (' ') +[ ('[') +scalar string (''day[1]'') +, (',') +whitespace (' ') +scalar string (''month[1]'') +, (',') +whitespace (' ') +scalar string (''year[1]'') +] (']') +Eol ('\n') +scalar key ('foo5:') +whitespace (' ') +[ ('[') +scalar dstring ('"?day"') +, (',') +whitespace (' ') +scalar dstring ('"?month"') +, (',') +whitespace (' ') +scalar dstring ('"?year"') +] (']') +Eol ('\n') +scalar key ('foo6:') +whitespace (' ') +[ ('[') +scalar string (''?day'') +, (',') +whitespace (' ') +scalar string (''?month'') +, (',') +whitespace (' ') +scalar string (''?year'') +] (']') +Eol ('\n') +scalar key ('foo7:') +whitespace (' ') +[ ('[') +scalar dstring ('"-day"') +, (',') +whitespace (' ') +scalar dstring ('"-month"') +, (',') +whitespace (' ') +scalar dstring ('"-year"') +] (']') +Eol ('\n') +scalar key ('foo8:') +whitespace (' ') +[ ('[') +scalar string (''-day'') +, (',') +whitespace (' ') +scalar string (''-month'') +, (',') +whitespace (' ') +scalar string (''-year'') +] (']') +Eol ('\n') +scalar key ('foo9:') +whitespace (' ') +[ ('[') +scalar dstring ('":day"') +, (',') +whitespace (' ') +scalar dstring ('":month"') +, (',') +whitespace (' ') +scalar dstring ('":year"') +] (']') +Eol ('\n') +scalar key ('foo10:') +whitespace (' ') +[ ('[') +scalar string ('':day'') +, (',') +whitespace (' ') +scalar string ('':month'') +, (',') +whitespace (' ') +scalar string ('':year'') +] (']') +Eol ('\n') +scalar key ('foo11:') +whitespace (' ') +tag ('!') +whitespace (' ') +scalar dstring ('"multi\n line\"\n string"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.yml new file mode 100644 index 000000000000..0f21caa77d72 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/strings.yml @@ -0,0 +1,13 @@ +foo1: ["day", "month", "year"] +foo2: ['day', 'month', 'year'] +foo3: ["day[1]", "month[1]", "year[1]"] +foo4: ['day[1]', 'month[1]', 'year[1]'] +foo5: ["?day", "?month", "?year"] +foo6: ['?day', '?month', '?year'] +foo7: ["-day", "-month", "-year"] +foo8: ['-day', '-month', '-year'] +foo9: [":day", ":month", ":year"] +foo10: [':day', ':month', ':year'] +foo11: ! "multi + line\" + string" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.txt new file mode 100644 index 000000000000..d73400cd1dc8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.txt @@ -0,0 +1,21 @@ +text ('%TAG !e! tag:example.com,2000:app/') +Eol ('\n') +--- ('---') +Eol ('\n') +- ('-') +whitespace (' ') +tag ('!local') +whitespace (' ') +text ('foo') +Eol ('\n') +- ('-') +whitespace (' ') +tag ('!!str') +whitespace (' ') +text ('bar') +Eol ('\n') +- ('-') +whitespace (' ') +tag ('!e!tag%21') +whitespace (' ') +text ('baz') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.yml new file mode 100644 index 000000000000..5f4ef93fe097 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/tagShorthands.yml @@ -0,0 +1,5 @@ +%TAG !e! tag:example.com,2000:app/ +--- +- !local foo +- !!str bar +- !e!tag%21 baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.txt new file mode 100644 index 000000000000..032cba577254 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.txt @@ -0,0 +1,17 @@ +scalar key ('body:') +whitespace (' ') +tag ('!!str') +whitespace (' ') +scalar list ('|-') +Eol ('\n') +indent (' ') +scalar list ('JVBER') +Eol ('\n') +scalar key ('body:') +whitespace (' ') +tag ('!!binary') +whitespace (' ') +scalar list ('|-') +Eol ('\n') +indent (' ') +scalar list ('JVBERi0xLjY') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.yml new file mode 100644 index 000000000000..25450e6708ba --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/typed_scalar_list.yml @@ -0,0 +1,4 @@ +body: !!str |- + JVBER +body: !!binary |- + JVBERi0xLjY \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.txt new file mode 100644 index 000000000000..edb56e1c96ce --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.txt @@ -0,0 +1,11 @@ +scalar key ('key:') +Eol ('\n') +indent (' ') +scalar key ('one:') +whitespace (' ') +text ('1 text') +Eol ('\n') +indent (' ') +scalar key ('other:') +whitespace (' ') +text ('{{count}} text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.yml new file mode 100644 index 000000000000..f97768be7f0a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection.yml @@ -0,0 +1,3 @@ +key: + one: 1 text + other: {{count}} text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.txt new file mode 100644 index 000000000000..b8c1ab6f9701 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.txt @@ -0,0 +1,11 @@ +scalar key ('key:') +Eol ('\n') +indent (' ') +scalar key ('one:') +whitespace (' ') +text ('1 text') +Eol ('\n') +indent (' ') +scalar key ('other:') +whitespace (' ') +text ('some {{count}} text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.yml new file mode 100644 index 000000000000..ab6f9f7a2f03 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/value_injection_2.yml @@ -0,0 +1,3 @@ +key: + one: 1 text + other: some {{count}} text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.txt new file mode 100644 index 000000000000..b186b6c57ed6 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.txt @@ -0,0 +1,8 @@ +tag ('!') +whitespace (' ') +scalar key ('foo :') +Eol ('\n') +indent (' ') +tag ('!') +whitespace (' ') +text ('baz') diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.yml new file mode 100644 index 000000000000..9e2afa410fd4 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/verbatimTags.yml @@ -0,0 +1,2 @@ +! foo : + ! baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.txt new file mode 100644 index 000000000000..11701495c738 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.txt @@ -0,0 +1,22 @@ +scalar key ('status:') +Eol ('\n') +indent (' ') +scalar key ('draft:') +whitespace (' ') +scalar dstring ('"Brouillon"') +whitespace (' ') +Eol ('\n') +indent (' ') +scalar key ('reviewed:') +whitespace (' ') +scalar dstring ('"Revise"') +Eol ('\n') +indent (' ') +scalar key ('hidden:') +whitespace (' ') +scalar dstring ('"Cache"') +Eol ('\n') +indent (' ') +scalar key ('published:') +whitespace (' ') +scalar dstring ('"Public"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.yml new file mode 100644 index 000000000000..7a0a5d36083d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/lexer/data/wrong_string_highlighting.yml @@ -0,0 +1,5 @@ +status: + draft: "Brouillon" + reviewed: "Revise" + hidden: "Cache" + published: "Public" diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/YAMLParserTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/YAMLParserTest.java new file mode 100644 index 000000000000..6c6973af0244 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/YAMLParserTest.java @@ -0,0 +1,220 @@ +package org.jetbrains.yaml.parser; + +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.testFramework.ParsingTestCase; +import org.jetbrains.yaml.YAMLParserDefinition; + +import java.io.IOException; + +/** + * @author oleg + */ +public class YAMLParserTest extends ParsingTestCase { + + public YAMLParserTest() { + super("", "yml", new YAMLParserDefinition()); + } + + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("yaml") + "/testSrc/org/jetbrains/yaml/parser/data/"; + } + + public void test2docs() throws Throwable { + doCodeTest("# Ranking of 1998 home runs\n" + + "---\n" + + "- Mark McGwire\n" + + "- Sammy Sosa\n" + + "- Ken Griffey\n" + + "\n" + + "# Team ranking\n" + + "---\n" + + "- Chicago Cubs\n" + + "- St Louis Cardinals"); + } + + public void testIndentation() throws Throwable { + doCodeTest("name: Mark McGwire\n" + + "accomplishment: >\n" + + " Mark set a major league\n" + + " home run record in 1998.\n" + + "stats: |\n" + + " 65 Home Runs\n" + + " 0.278 Batting Average"); + } + + public void testMap_between_seq() throws Throwable { + doCodeTest("?\n" + + " - Detroit Tigers\n" + + " - Chicago cubs\n" + + ":\n" + + " - 2001-07-23\n" + + "\n" + + "? [ New York Yankees,\n" + + " Atlanta Braves ]\n" + + ": [ 2001-07-02, 2001-08-12,\n" + + " 2001-08-14 ]"); + } + + public void testMap_map() throws Throwable { + doCodeTest("Mark McGwire: {hr: 65, avg: 0.278}\n" + + "Sammy Sosa: {\n" + + " hr: 63,\n" + + " avg: 0.288\n" + + " }"); + } + + public void testSample_log() throws Throwable { + doCodeTest("Stack:\n" + + " - file: TopClass.py\n" + + " line: 23\n" + + " code: |\n" + + " x = MoreObject(\"345\\n\")\n" + + " - file: MoreClass.py\n" + + " line: 58\n" + + " code: |-\n" + + " foo = bar"); + } + + public void testSeq_seq() throws Throwable { + doCodeTest("- [name , hr, avg ]\n" + + "- [Mark McGwire, 65, 0.278]\n" + + "- [Sammy Sosa , 63, 0.288]"); + } + + public void testSequence_mappings() throws Throwable { + doCodeTest("-\n" + + " name: Mark McGwire\n" + + " hr: 65\n" + + " avg: 0.278\n" + + "-\n" + + " name: Sammy Sosa\n" + + " hr: 63\n" + + " avg: 0.288"); + } + + public void testBalance() throws Throwable { + doCodeTest("runningTime: 150000\n" + + "scenarios:\n" + + " voice_bundle_change: {\n" + + " dataCycling: true\n" + + " }\n" + + " smart_overview: {\n" + + " dataCycling: true\n" + + " }"); + } + + public void testInterpolation() throws Throwable { + doCodeTest("en:\n foo: bar %{baz}"); + } + + public void testValue_injection() throws Throwable { + doCodeTest("key:\n" + " one: 1 text\n" + " other: some {{count}} text"); + } + + public void testSequence_idea76804() throws Throwable { + doCodeTest("server:\n" + + "- a\n" + + "- b\n" + + "\n" + + "server:\n" + + " - a\n" + + " - b"); + } + + public void testMultiline_ruby16796() throws Throwable { + doCodeTest("code:\n" + + " src=\"keys/{{item}}\"\n" + + " mode=0600\n" + + "with_items:\n" + + " - \"id_rsa.pub\"\n"); + } + + public void testRuby17389() throws Throwable { + doCodeTest("---\n" + + "foo: {}\n" + + "bar: \"baz\""); + } + + public void testRuby15345() throws IOException { + doCodeTest("- !qualified.class.name\n" + + " propertyOne: bla bla\n" + + " propertyWithOneSequence:\n" + + " - first value\n" + + " nextPropertyWithOneSequence:\n" + + " - first value of another sequence"); + } + + public void testHonestMultiline() throws Throwable { + doCodeTest("---\n" + + "foo: >\n" + + " first text line\n" + + " second text line\n" + + "\n" + + " baz: clazz\n" + + " - this is text\n" + + " - but looks like a list\n" + + " - indent tells.\n" + + "bar: zoo"); + } + + public void testEmptyMultiline() throws Throwable { + doCodeTest("---\n" + + "foo: >\n" + + "bar:\n" + + " abc: def\n" + + " ghi: >\n" + + " jkl: mno\n" + + "baz: qwe"); + } + + public void testIncompleteKey() throws Throwable { + doCodeTest("logging:\n" + + " config: bla\n" + + " index"); + } + + public void testStringWithTag() throws IOException { + doCodeTest("foo: ! \"tratata\""); + } + + public void testIncompleteKeyWithWhitespace() throws IOException { + doCodeTest("logging:\n" + + " config:\n" + + " \n" + + " \n" + + " \n" + + " \n"); + } + + public void testExplicitMaps() { + doTest(true); + } + + public void testSpec2_27() { + doTest(true); + } + + public void testAnsibleRoleElkInit() { + doTest(true); + } + + public void testAnsibleRoleElkMain() { + doTest(true); + } + + public void testBlockMapping() { + doTest(true); + } + + public void testIncompleteKeyInHierarchy() { + doTest(true); + } + + public void testKeyValueWithEmptyLineAhead() { + doTest(true); + } + + public void testMultipleDocsWithMappings() { + doTest(true); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/2docs.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/2docs.txt new file mode 100644 index 000000000000..d429d9a5c3f7 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/2docs.txt @@ -0,0 +1,43 @@ +YAML file + PsiComment(comment)('# Ranking of 1998 home runs') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Mark McGwire') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Sammy Sosa') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Ken Griffey') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + PsiComment(comment)('# Team ranking') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Chicago Cubs') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('St Louis Cardinals') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.txt new file mode 100644 index 000000000000..d64d8badfae4 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.txt @@ -0,0 +1,82 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Validate logstash_configs variable') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('assert:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('that:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('logstash_configs != ''') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('stat:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('path={{ logstash_configs }}/config') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('delegate_to:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('127.0.0.1') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('register:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('p') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Validate config subdirectory') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('assert:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('that:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('p.stat.isdir is defined and p.stat.isdir') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.yml new file mode 100644 index 000000000000..304ace17796f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkInit.yml @@ -0,0 +1,12 @@ +--- +- name: Validate logstash_configs variable + assert: + that: + - logstash_configs != '' +- stat: path={{ logstash_configs }}/config + delegate_to: 127.0.0.1 + register: p +- name: Validate config subdirectory + assert: + that: + - p.stat.isdir is defined and p.stat.isdir \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.txt new file mode 100644 index 000000000000..881dfd7f89e1 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.txt @@ -0,0 +1,388 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('include:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('init.yml') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Create directory') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('file:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('path={{ directory }} state=directory') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Copy Elasticsearch configuration') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('file:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('path={{ directory }}/config/elasticsearch/ state=directory') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('template:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('src=elasticsearch.yml dest={{ directory }}/config/elasticsearch/') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('notify:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Restart Elasticsearch') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('copy:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('src=logging.yml dest={{ directory }}/config/elasticsearch/') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('notify:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Restart Elasticsearch') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Start Elasticsearch docker container') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('docker:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('elasticsearch') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('image:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('elasticsearch:{{ elasticsearch_version }}') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('volumes:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ directory }}/config/elasticsearch/:/usr/share/elasticsearch/config/:ro"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ directory }}/data/:/usr/share/elasticsearch/data/"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('ports:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ elasticsearch_port }}:9200"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('state:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('started') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('restart_policy:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('always') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Copy Logstash configuration') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('synchronize:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('src={{ logstash_configs }}/ dest={{ directory }}/config/logstash/ delete=yes') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('notify:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Restart Logstash') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Start Logstash docker container') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('docker:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('logstash') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('image:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('mkuzmin/logstash') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('volumes:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ directory }}/config/logstash/:/opt/logstash/config/:ro"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('links:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"elasticsearch"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('command:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('-f /opt/logstash/config/config/') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('expose:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ logstash_port }}"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('ports:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ logstash_port }}:{{ logstash_port }}"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('state:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('started') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('restart_policy:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('always') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Copy Kibana configuration') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('file:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('path={{ directory }}/config/kibana state=directory') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('template:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('src=kibana.yml dest={{ directory }}/config/kibana/') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Start Kibana docker container') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('docker:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('kibana') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('image:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('kibana:{{ kibana_version }}') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('volumes:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ directory }}/config/kibana/:/opt/kibana/config/"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('links:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"elasticsearch"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('ports:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"{{ kibana_port }}:5601"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('state:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('started') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('restart_policy:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('always') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.yml new file mode 100644 index 000000000000..b72cae342aa2 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/AnsibleRoleElkMain.yml @@ -0,0 +1,58 @@ +--- +- include: init.yml + +- name: Create directory + file: path={{ directory }} state=directory + +- name: Copy Elasticsearch configuration + file: path={{ directory }}/config/elasticsearch/ state=directory +- template: src=elasticsearch.yml dest={{ directory }}/config/elasticsearch/ + notify: Restart Elasticsearch +- copy: src=logging.yml dest={{ directory }}/config/elasticsearch/ + notify: Restart Elasticsearch +- name: Start Elasticsearch docker container + docker: + name: elasticsearch + image: elasticsearch:{{ elasticsearch_version }} + volumes: + - "{{ directory }}/config/elasticsearch/:/usr/share/elasticsearch/config/:ro" + - "{{ directory }}/data/:/usr/share/elasticsearch/data/" + ports: + - "{{ elasticsearch_port }}:9200" + state: started + restart_policy: always + +- name: Copy Logstash configuration + synchronize: src={{ logstash_configs }}/ dest={{ directory }}/config/logstash/ delete=yes + notify: Restart Logstash +- name: Start Logstash docker container + docker: + name: logstash + image: mkuzmin/logstash + volumes: + - "{{ directory }}/config/logstash/:/opt/logstash/config/:ro" + links: + - "elasticsearch" + command: -f /opt/logstash/config/config/ + expose: + - "{{ logstash_port }}" + ports: + - "{{ logstash_port }}:{{ logstash_port }}" + state: started + restart_policy: always + +- name: Copy Kibana configuration + file: path={{ directory }}/config/kibana state=directory +- template: src=kibana.yml dest={{ directory }}/config/kibana/ +- name: Start Kibana docker container + docker: + name: kibana + image: kibana:{{ kibana_version }} + volumes: + - "{{ directory }}/config/kibana/:/opt/kibana/config/" + links: + - "elasticsearch" + ports: + - "{{ kibana_port }}:5601" + state: started + restart_policy: always \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Balance.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Balance.txt new file mode 100644 index 000000000000..121a1eda0a59 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Balance.txt @@ -0,0 +1,46 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('runningTime:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('150000') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('scenarios:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('voice_bundle_change:') + PsiWhiteSpace(' ') + YAML hash + PsiElement({)('{') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('dataCycling:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('true') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(})('}') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('smart_overview:') + PsiWhiteSpace(' ') + YAML hash + PsiElement({)('{') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('dataCycling:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('true') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.txt new file mode 100644 index 000000000000..931f55800258 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.txt @@ -0,0 +1,13 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('bar:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('baz') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.yml new file mode 100644 index 000000000000..60f55c1e23cd --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/BlockMapping.yml @@ -0,0 +1,2 @@ +foo: + bar: baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/EmptyMultiline.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/EmptyMultiline.txt new file mode 100644 index 000000000000..1c63b71fa3ff --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/EmptyMultiline.txt @@ -0,0 +1,41 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiWhiteSpace(' ') + YAML scalar text + PsiElement(scalar text)('>') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('bar:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('abc:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('def') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('ghi:') + PsiWhiteSpace(' ') + YAML scalar text + PsiElement(scalar text)('>') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('jkl:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('mno') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('baz:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('qwe') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.txt new file mode 100644 index 000000000000..97f890f0cd6c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.txt @@ -0,0 +1,174 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML mapping + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('explicit key') + PsiWhiteSpace(' ') + PsiComment(comment)('# Empty value') + PsiElement(Eol)('\n') + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML scalar list + PsiElement(scalar list)('|') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('block key') + PsiElement(Eol)('\n') + PsiElement(:)(':') + PsiWhiteSpace(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('one') + PsiWhiteSpace(' ') + PsiComment(comment)('# Explicit compact') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('two') + PsiWhiteSpace(' ') + PsiComment(comment)('# block value') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML hash + PsiElement(tag)('!!map') + PsiWhiteSpace(' ') + PsiElement({)('{') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(tag)('!!str') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('"explicit key"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(:)(':') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(tag)('!!str') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('""') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(tag)('!!str') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('"block key\n"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(:)(':') + PsiWhiteSpace(' ') + YAML array + PsiElement(tag)('!!seq') + PsiWhiteSpace(' ') + PsiElement([)('[') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + YAML quoted text + PsiElement(tag)('!!str') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('"one"') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + YAML quoted text + PsiElement(tag)('!!str') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('"two"') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(])(']') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(})('}') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('sun:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('yellow↓') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('earth:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('blue↓') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(:)(':') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('moon:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('white↓') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML hash + PsiElement({)('{') + PsiElement(Eol)('\n') + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + PsiElement(scalar key)('explicit:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('entry') + PsiElement(,)(',') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('implicit:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('entry') + PsiElement(,)(',') + PsiElement(Eol)('\n') + YAML key value + PsiElement(?)('?') + PsiElement(Eol)('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.yml new file mode 100644 index 000000000000..9bdfe33a075f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/ExplicitMaps.yml @@ -0,0 +1,29 @@ +--- +? explicit key # Empty value +? | + block key +: - one # Explicit compact + - two # block value + +--- +!!map { + ? !!str "explicit key" + : !!str "", + ? !!str "block key\n" + : !!seq [ + !!str "one", + !!str "two", + ], +} + +--- +- sun: yellow↓ +- ? earth: blue↓ + : moon: white↓ + +--- +{ +? explicit: entry, +implicit: entry, +? +} \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/HonestMultiline.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/HonestMultiline.txt new file mode 100644 index 000000000000..baee0e5850f2 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/HonestMultiline.txt @@ -0,0 +1,35 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiWhiteSpace(' ') + YAML scalar text + PsiElement(scalar text)('>') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('first text line') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('second text line') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('baz: clazz') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('- this is text') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('- but looks like a list') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('- indent tells.') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('bar:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('zoo') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKey.txt new file mode 100644 index 000000000000..4a1af2b591e0 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKey.txt @@ -0,0 +1,17 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('logging:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('config:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('bla') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML plain scalar text + PsiElement(text)('index') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.txt new file mode 100644 index 000000000000..0dc0ac9fb07e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.txt @@ -0,0 +1,17 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('bar:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('baz:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('taz') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.yml new file mode 100644 index 000000000000..ab13dddfae8f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyInHierarchy.yml @@ -0,0 +1,3 @@ +foo: + bar: + baz: taz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyWithWhitespace.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyWithWhitespace.txt new file mode 100644 index 000000000000..3017769d7157 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/IncompleteKeyWithWhitespace.txt @@ -0,0 +1,19 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('logging:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('config:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(Eol)('\n') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Indentation.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Indentation.txt new file mode 100644 index 000000000000..e12b0f427446 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Indentation.txt @@ -0,0 +1,32 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Mark McGwire') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('accomplishment:') + PsiWhiteSpace(' ') + YAML scalar text + PsiElement(scalar text)('>') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('Mark set a major league') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar text)('home run record in 1998.') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('stats:') + PsiWhiteSpace(' ') + YAML scalar list + PsiElement(scalar list)('|') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('65 Home Runs') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('0.278 Batting Average') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Interpolation.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Interpolation.txt new file mode 100644 index 000000000000..3bb7bfacd6b5 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Interpolation.txt @@ -0,0 +1,13 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('en:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('bar %{baz}') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.txt new file mode 100644 index 000000000000..c0366007db2d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.txt @@ -0,0 +1,102 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('application:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('gaeproject') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('version:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('1') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('runtime:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('python27') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('api_version:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('1') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('threadsafe:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('yes') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('handlers:') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('url:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('/favicon\.ico') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('static_files:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('favicon.ico') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('upload:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('favicon\.ico') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('url:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('.*') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('script:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('test/main.app') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('libraries:') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('webapp2') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('version:') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"2.5.2"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.yml new file mode 100644 index 000000000000..22cdbbcb5786 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/KeyValueWithEmptyLineAhead.yml @@ -0,0 +1,17 @@ +application: gaeproject +version: 1 +runtime: python27 +api_version: 1 +threadsafe: yes + +handlers: +- url: /favicon\.ico + static_files: favicon.ico + upload: favicon\.ico + +- url: .* + script: test/main.app + +libraries: +- name: webapp2 + version: "2.5.2" diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_between_seq.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_between_seq.txt new file mode 100644 index 000000000000..4ea161fa11be --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_between_seq.txt @@ -0,0 +1,71 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(?)('?') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Detroit Tigers') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Chicago cubs') + PsiElement(Eol)('\n') + PsiElement(:)(':') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('2001-07-23') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML key value + PsiElement(?)('?') + PsiWhiteSpace(' ') + YAML array + PsiElement([)('[') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('New York Yankees') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('Atlanta Braves') + PsiWhiteSpace(' ') + PsiElement(])(']') + PsiElement(Eol)('\n') + PsiElement(:)(':') + PsiWhiteSpace(' ') + YAML array + PsiElement([)('[') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('2001-07-02') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('2001-08-12') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('2001-08-14') + PsiWhiteSpace(' ') + PsiElement(])(']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_map.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_map.txt new file mode 100644 index 000000000000..3d1780cd899e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Map_map.txt @@ -0,0 +1,45 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('Mark McGwire:') + PsiWhiteSpace(' ') + YAML hash + PsiElement({)('{') + YAML key value + PsiElement(scalar key)('hr:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('65') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML key value + PsiElement(scalar key)('avg:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('0.278') + PsiElement(})('}') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('Sammy Sosa:') + PsiWhiteSpace(' ') + YAML hash + PsiElement({)('{') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('hr:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('63') + PsiElement(,)(',') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('avg:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('0.288') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Multiline_ruby16796.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Multiline_ruby16796.txt new file mode 100644 index 000000000000..61c3d553e2ff --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Multiline_ruby16796.txt @@ -0,0 +1,24 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('code:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML plain scalar text + PsiElement(text)('src="keys/{{item}}"') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(text)('mode=0600') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('with_items:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"id_rsa.pub"') + PsiElement(Eol)('\n') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.txt new file mode 100644 index 000000000000..9cad908d15d4 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.txt @@ -0,0 +1,38 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('spring:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('application:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('bar') + PsiElement(Eol)('\n') + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML mapping + YAML key value + PsiElement(scalar key)('spring:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('application:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('bar') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.yml new file mode 100644 index 000000000000..8d21e2051b14 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/MultipleDocsWithMappings.yml @@ -0,0 +1,7 @@ +spring: + application: + name: bar +--- +spring: + application: + name: bar \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby15345.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby15345.txt new file mode 100644 index 000000000000..e760347b01d2 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby15345.txt @@ -0,0 +1,39 @@ +YAML file + YAML document + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + PsiElement(tag)('!qualified.class.name') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('propertyOne:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('bla bla') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('propertyWithOneSequence:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('first value') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('nextPropertyWithOneSequence:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('first value of another sequence') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby17389.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby17389.txt new file mode 100644 index 000000000000..f17805834322 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Ruby17389.txt @@ -0,0 +1,17 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiElement(Eol)('\n') + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiWhiteSpace(' ') + YAML hash + PsiElement({)('{') + PsiElement(})('}') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('bar:') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(scalar dstring)('"baz"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sample_log.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sample_log.txt new file mode 100644 index 000000000000..74e95e573ea8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sample_log.txt @@ -0,0 +1,62 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('Stack:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('file:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('TopClass.py') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('line:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('23') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('code:') + PsiWhiteSpace(' ') + YAML scalar list + PsiElement(scalar list)('|') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('x = MoreObject("345\n")') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('file:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('MoreClass.py') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('line:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('58') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('code:') + PsiWhiteSpace(' ') + YAML scalar list + PsiElement(scalar list)('|-') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('foo = bar') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Seq_seq.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Seq_seq.txt new file mode 100644 index 000000000000..a823b6a2c544 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Seq_seq.txt @@ -0,0 +1,65 @@ +YAML file + YAML document + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML array + PsiElement([)('[') + YAML sequence item + YAML plain scalar text + PsiElement(text)('name') + PsiWhiteSpace(' ') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('hr') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('avg') + PsiWhiteSpace(' ') + PsiElement(])(']') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML array + PsiElement([)('[') + YAML sequence item + YAML plain scalar text + PsiElement(text)('Mark McGwire') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('65') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('0.278') + PsiElement(])(']') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML array + PsiElement([)('[') + YAML sequence item + YAML plain scalar text + PsiElement(text)('Sammy Sosa') + PsiWhiteSpace(' ') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('63') + PsiElement(,)(',') + PsiWhiteSpace(' ') + YAML sequence item + YAML plain scalar text + PsiElement(text)('0.288') + PsiElement(])(']') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_idea76804.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_idea76804.txt new file mode 100644 index 000000000000..e567216f68be --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_idea76804.txt @@ -0,0 +1,37 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('server:') + PsiElement(Eol)('\n') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('a') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('b') + PsiElement(Eol)('\n') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('server:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('a') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('b') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_mappings.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_mappings.txt new file mode 100644 index 000000000000..f6bd524f72cd --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Sequence_mappings.txt @@ -0,0 +1,52 @@ +YAML file + YAML document + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Mark McGwire') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('hr:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('65') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('avg:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('0.278') + PsiElement(Eol)('\n') + YAML sequence item + PsiElement(-)('-') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('name:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Sammy Sosa') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('hr:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('63') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('avg:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('0.288') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.txt new file mode 100644 index 000000000000..c2849d3fdecb --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.txt @@ -0,0 +1,177 @@ +YAML file + YAML document + PsiElement(---)('---') + PsiWhiteSpace(' ') + YAML mapping + PsiElement(tag)('!') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('invoice:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('34843') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('date :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('2001-01-23') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('bill-to:') + PsiWhiteSpace(' ') + YAML mapping + YAML plain scalar text + PsiElement(text)('&id001') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('given :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Chris') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('family :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Dumars') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('address:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('lines:') + PsiWhiteSpace(' ') + YAML scalar list + PsiElement(scalar list)('|') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('458 Walkman Dr.') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(scalar list)('Suite #292') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('city :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Royal Oak') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('state :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('MI') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('postal :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('48046') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('ship-to:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('*id001') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('product:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('sku :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('BL394D') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('quantity :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('4') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('description :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Basketball') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('price :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('450.00') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML sequence item + PsiElement(-)('-') + PsiWhiteSpace(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('sku :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('BL4438H') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('quantity :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('1') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('description :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('Super Hoop') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('price :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('2392.00') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('tax :') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('251.42') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('total:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('4443.52') + PsiElement(Eol)('\n') + YAML key value + PsiElement(scalar key)('comments:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML plain scalar text + PsiElement(text)('Late afternoon is best.') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(text)('Backup contact is Nancy') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + PsiElement(text)('Billsmer @ 338-4338.') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.yml new file mode 100644 index 000000000000..82c69d62802f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Spec2_27.yml @@ -0,0 +1,29 @@ +--- ! +invoice: 34843 +date : 2001-01-23 +bill-to: &id001 + given : Chris + family : Dumars + address: + lines: | + 458 Walkman Dr. + Suite #292 + city : Royal Oak + state : MI + postal : 48046 +ship-to: *id001 +product: + - sku : BL394D + quantity : 4 + description : Basketball + price : 450.00 + - sku : BL4438H + quantity : 1 + description : Super Hoop + price : 2392.00 +tax : 251.42 +total: 4443.52 +comments: + Late afternoon is best. + Backup contact is Nancy + Billsmer @ 338-4338. \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/StringWithTag.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/StringWithTag.txt new file mode 100644 index 000000000000..95cce29c6112 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/StringWithTag.txt @@ -0,0 +1,10 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('foo:') + PsiWhiteSpace(' ') + YAML quoted text + PsiElement(tag)('!') + PsiWhiteSpace(' ') + PsiElement(scalar dstring)('"tratata"') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Value_injection.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Value_injection.txt new file mode 100644 index 000000000000..81750b525abb --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/parser/data/Value_injection.txt @@ -0,0 +1,20 @@ +YAML file + YAML document + YAML mapping + YAML key value + PsiElement(scalar key)('key:') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML mapping + YAML key value + PsiElement(scalar key)('one:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('1 text') + PsiElement(Eol)('\n') + PsiElement(indent)(' ') + YAML key value + PsiElement(scalar key)('other:') + PsiWhiteSpace(' ') + YAML plain scalar text + PsiElement(text)('some {{count}} text') \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/YAMLScalarContentTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/YAMLScalarContentTest.java new file mode 100644 index 000000000000..ed173e790812 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/YAMLScalarContentTest.java @@ -0,0 +1,87 @@ +package org.jetbrains.yaml.psi; + +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import org.jetbrains.yaml.YAMLParserDefinition; + +public class YAMLScalarContentTest extends LightPlatformCodeInsightFixtureTestCase { + @Override + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("yaml") + "/testSrc/org/jetbrains/yaml/psi/data/"; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + new YAMLParserDefinition(); + } + + public void testPlainScalar1() { + doTest(); + } + + public void testPlainScalar2() { + doTest(); + } + + public void testPlainScalar3() { + doTest(); + } + + public void testLiteralStyle1() { + doTest(); + } + + public void testLiteralStyle2() { + doTest(); + } + + public void testLiteralStyle3() { + doTest(); + } + + public void testFoldedStyle1() { + doTest(); + } + + public void testFoldedStyle2() { + doTest(); + } + + public void testFoldedStyle3() { + doTest(); + } + + public void testFoldedStyle4() { + doTest(); + } + + public void testSingleQuote1() { + doTest(); + } + + public void testSingleQuote2() { + doTest(); + } + + public void testDoubleQuote1() { + doTest(); + } + + public void testDoubleQuote2() { + doTest(); + } + + private void doTest() { + myFixture.configureByFile(getTestName(true) + ".yml"); + + final int offset = myFixture.getCaretOffset(); + final PsiElement elementAtCaret = myFixture.getFile().findElementAt(offset); + final YAMLScalar scalarElement = PsiTreeUtil.getNonStrictParentOfType(elementAtCaret, YAMLScalar.class); + assertNotNull(scalarElement); + + assertSameLinesWithFile(getTestDataPath() + getTestName(true) + ".txt", scalarElement.getTextValue(), false); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.txt new file mode 100644 index 000000000000..c9b6817ccd23 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.txt @@ -0,0 +1,2 @@ +folded to a space, +to a line feed, or non-content \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.yml new file mode 100644 index 000000000000..6549a118d312 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote1.yml @@ -0,0 +1,5 @@ +"folded +to a space, + +to a line feed, or \ + \ non-content" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.txt new file mode 100644 index 000000000000..a39daa3f95ff --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.txt @@ -0,0 +1,2 @@ + 1st non-empty +2nd non-empty 3rd non-empty \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.yml new file mode 100644 index 000000000000..3dd52649971e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/doubleQuote2.yml @@ -0,0 +1,4 @@ +" 1st non-empty + + 2nd non-empty + 3rd non-empty " \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.txt new file mode 100644 index 000000000000..d675fa44e506 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.txt @@ -0,0 +1 @@ +foo bar diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.yml new file mode 100644 index 000000000000..e9c7afbb219f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle1.yml @@ -0,0 +1,3 @@ +> + foo + bar \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.txt new file mode 100644 index 000000000000..34f5443cadf6 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.txt @@ -0,0 +1,3 @@ + +foo +bar diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.yml new file mode 100644 index 000000000000..b94fa3ceb43f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle2.yml @@ -0,0 +1,5 @@ +> + + foo + + bar diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.txt new file mode 100644 index 000000000000..65cf3269b11a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.txt @@ -0,0 +1,3 @@ +foo + bar +baz diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.yml new file mode 100644 index 000000000000..225c5e38c751 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle3.yml @@ -0,0 +1,4 @@ +> + foo + bar + baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.txt new file mode 100644 index 000000000000..dd52fe1a9aeb --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.txt @@ -0,0 +1,9 @@ + +folded line +next line + * bullet + + * list + * line + +last line diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.yml new file mode 100644 index 000000000000..053809f01c1e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/foldedStyle4.yml @@ -0,0 +1,16 @@ +> + + folded + line + + next + line + * bullet + + * list + * line + + last + line + +# Comment \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.txt new file mode 100644 index 000000000000..37ddcb494305 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.txt @@ -0,0 +1,2 @@ +literal +text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.yml new file mode 100644 index 000000000000..c2d1810c30c6 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle1.yml @@ -0,0 +1,3 @@ +--- | + literal + text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.txt new file mode 100644 index 000000000000..4c2f05aef7a7 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.txt @@ -0,0 +1,2 @@ +literal + text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.yml new file mode 100644 index 000000000000..7fa415fb9c0d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle2.yml @@ -0,0 +1,4 @@ +| + literal + text + diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.txt new file mode 100644 index 000000000000..8273a5b9e380 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.txt @@ -0,0 +1,6 @@ + + +literal + + +text diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.yml new file mode 100644 index 000000000000..d5886c52b07a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/literalStyle3.yml @@ -0,0 +1,9 @@ +| + + + literal + + + text + +# Comment diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.txt new file mode 100644 index 000000000000..31382bef9edf --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.txt @@ -0,0 +1 @@ +foo bar baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.yml new file mode 100644 index 000000000000..7fe3450b3061 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar1.yml @@ -0,0 +1,3 @@ +foo +bar +baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.txt new file mode 100644 index 000000000000..88e45e9243bc --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.txt @@ -0,0 +1,5 @@ +foo bar + +baz + +fofo \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.yml new file mode 100644 index 000000000000..fde3d2239ada --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar2.yml @@ -0,0 +1,8 @@ +foo + bar + + +baz + + + fofo \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.txt new file mode 100644 index 000000000000..bfd5a52af53c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.txt @@ -0,0 +1,3 @@ +foo bar far +baz +baaaz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.yml new file mode 100644 index 000000000000..5f344d6a9c36 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/plainScalar3.yml @@ -0,0 +1,7 @@ +- foo + bar + far + + baz + + baaaz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.txt new file mode 100644 index 000000000000..a2ea44eb512d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.txt @@ -0,0 +1 @@ +here's to "quotes" \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.yml new file mode 100644 index 000000000000..c4b4ca9a0806 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote1.yml @@ -0,0 +1 @@ +'here''s to "quotes"' \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.txt new file mode 100644 index 000000000000..a39daa3f95ff --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.txt @@ -0,0 +1,2 @@ + 1st non-empty +2nd non-empty 3rd non-empty \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.yml new file mode 100644 index 000000000000..7bf9c02b32b3 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psi/data/singleQuote2.yml @@ -0,0 +1,4 @@ +' 1st non-empty + + 2nd non-empty + 3rd non-empty ' diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/YAMLMappingModificationTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/YAMLMappingModificationTest.java new file mode 100644 index 000000000000..497574aa0e00 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/YAMLMappingModificationTest.java @@ -0,0 +1,118 @@ +package org.jetbrains.yaml.psiModification; + +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.YAMLUtil; +import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLKeyValue; +import org.jetbrains.yaml.psi.YAMLMapping; + +public class YAMLMappingModificationTest extends LightPlatformCodeInsightFixtureTestCase { + @Override + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("yaml") + "/testSrc/org/jetbrains/yaml/psiModification/data/"; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + } + + // TODO make + + public void testCreateKeyInEmptyFile() { + doMappingTest("key", "value"); + } + + public void testCreateSecondTopLevelKey() { + doMappingTest("key2", "value2"); + } + + public void testReplaceTopLevelKey() { + doMappingTest("key", "value2"); + } + + public void testCreateSecondKeyLevelTwo() { + doMappingTest("key", "value"); + } + + public void testCreateSecondKeyLevelTwoCompact() { + doMappingTest("key", "value"); + } + + public void testReplaceValueScalarScalar() { + doValueTest("newValue"); + } + + public void testReplaceValueCompoundScalar() { + doValueTest("newValue"); + } + + public void testReplaceValueScalarCompound() { + doValueTest("someKey: - bla\n - bla"); + } + + public void testSetValueScalar() { + doValueTest("newValue"); + } + + public void testSetValueCompound() { + doValueTest("someKey: - bla\n" + + " - bla"); + } + + private void doValueTest(final String valueText) { + myFixture.configureByFile(getTestName(true) + ".yml"); + final int offset = myFixture.getCaretOffset(); + final PsiElement elementAtCaret = myFixture.getFile().findElementAt(offset); + final YAMLKeyValue keyValue = PsiTreeUtil.getParentOfType(elementAtCaret, YAMLKeyValue.class, false); + assertNotNull(keyValue); + + final YAMLKeyValue dummyKV = YAMLElementGenerator.getInstance(myFixture.getProject()).createYamlKeyValue("foo", valueText); + assertNotNull(dummyKV.getValue()); + + WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() { + @Override + public void run() { + keyValue.setValue(dummyKV.getValue()); + } + }); + + assertSameLinesWithFile(getTestDataPath() + getTestName(true) + ".txt", myFixture.getFile().getText(), false); + } + + private void doMappingTest(final String key, final String content) { + myFixture.configureByFile(getTestName(true) + ".yml"); + + final int offset = myFixture.getCaretOffset(); + final PsiElement elementAtCaret = myFixture.getFile().findElementAt(offset); + final YAMLMapping mapping = PsiTreeUtil.getParentOfType(elementAtCaret, YAMLMapping.class, false); + + if (mapping == null) { + YAMLUtil.createI18nRecord((YAMLFile)myFixture.getFile(), new String[]{key}, content); + } + else { + assertNotNull(mapping); + + //final int indent = YAMLUtil.getIndentInThisLine(mapping); + //final String indentString = StringUtil.repeatSymbol(' ', indent); + + final YAMLKeyValue dummyKeyValue = YAMLElementGenerator.getInstance(myFixture.getProject()).createYamlKeyValue(key, content); + assertNotNull(dummyKeyValue); + + WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() { + @Override + public void run() { + mapping.putKeyValue(dummyKeyValue); + } + }); + } + + assertSameLinesWithFile(getTestDataPath() + getTestName(true) + ".txt", myFixture.getFile().getText(), false); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createKeyInEmptyFile.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createKeyInEmptyFile.txt new file mode 100644 index 000000000000..9f601f13509c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createKeyInEmptyFile.txt @@ -0,0 +1 @@ +key: value \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createKeyInEmptyFile.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createKeyInEmptyFile.yml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.txt new file mode 100644 index 000000000000..e1c0a7601c26 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.txt @@ -0,0 +1,3 @@ +foo: + bar: baz + key: value \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.yml new file mode 100644 index 000000000000..23659ebfe9e0 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwo.yml @@ -0,0 +1,2 @@ +foo: + bar: baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.txt new file mode 100644 index 000000000000..740421b64b8e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.txt @@ -0,0 +1,2 @@ +- bar: baz + key: value \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.yml new file mode 100644 index 000000000000..38ed6aca307e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondKeyLevelTwoCompact.yml @@ -0,0 +1 @@ +- bar: baz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.txt new file mode 100644 index 000000000000..dc626fedd46f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.txt @@ -0,0 +1,2 @@ +key: value +key2: value2 \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.yml new file mode 100644 index 000000000000..9f601f13509c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/createSecondTopLevelKey.yml @@ -0,0 +1 @@ +key: value \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.txt new file mode 100644 index 000000000000..1a3a0e02327b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.txt @@ -0,0 +1 @@ +key: value2 \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.yml new file mode 100644 index 000000000000..9f601f13509c --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceTopLevelKey.yml @@ -0,0 +1 @@ +key: value \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.txt new file mode 100644 index 000000000000..2f774d5c951b --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.txt @@ -0,0 +1,3 @@ +foo: + bar: newValue + taz: niz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.yml new file mode 100644 index 000000000000..d1d61adf613f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueCompoundScalar.yml @@ -0,0 +1,4 @@ +foo: + bar: + baz: vaz + taz: niz \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.txt new file mode 100644 index 000000000000..2815d164fc06 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.txt @@ -0,0 +1,5 @@ +foo: + bar: + someKey: - bla + - bla + baba: papa \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.yml new file mode 100644 index 000000000000..d8864ac7b53d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarCompound.yml @@ -0,0 +1,3 @@ +foo: + bar: baz + baba: papa \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.txt new file mode 100644 index 000000000000..9d5ce4c7b44a --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.txt @@ -0,0 +1,3 @@ +foo: + bar: newValue + baba: papa \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.yml new file mode 100644 index 000000000000..d8864ac7b53d --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/replaceValueScalarScalar.yml @@ -0,0 +1,3 @@ +foo: + bar: baz + baba: papa \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.txt new file mode 100644 index 000000000000..61483892cfda --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.txt @@ -0,0 +1,5 @@ +foo: + bar: + someKey: - bla + - bla + baz: afoo \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.yml new file mode 100644 index 000000000000..62e9724b0ec8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueCompound.yml @@ -0,0 +1,3 @@ +foo: + bar: + baz: afoo \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.txt new file mode 100644 index 000000000000..440566f70559 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.txt @@ -0,0 +1,3 @@ +foo: + bar: newValue + baz: afoo \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.yml new file mode 100644 index 000000000000..62e9724b0ec8 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/psiModification/data/setValueScalar.yml @@ -0,0 +1,3 @@ +foo: + bar: + baz: afoo \ No newline at end of file diff --git a/plugins/yaml/yaml.iml b/plugins/yaml/yaml.iml new file mode 100644 index 000000000000..d5d9c0de125c --- /dev/null +++ b/plugins/yaml/yaml.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py index 379c9f7bcc32..789923211726 100644 --- a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py +++ b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py @@ -239,7 +239,7 @@ class ThreadingLogger: traceback.print_exc() -class NameManager(): +class NameManager: def __init__(self, name_prefix): self.tasks = {} self.last = 0 diff --git a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py index 7d9e908a7f82..69e817b14c71 100644 --- a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py +++ b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py @@ -1,7 +1,9 @@ import _pydev_threading as threading -import functools - +try: + import functools +except: + pass def wrapper(fun): def pydev_after_run_call(): diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java index df8460608f53..d73539b2f8ef 100644 --- a/python/psi-api/src/com/jetbrains/python/PyNames.java +++ b/python/psi-api/src/com/jetbrains/python/PyNames.java @@ -165,6 +165,7 @@ public class PyNames { public static final String NAME = "__name__"; public static final String ENTER = "__enter__"; + public static final String EXIT = "__exit__"; public static final String CALLABLE_BUILTIN = "callable"; public static final String NAMEDTUPLE = "namedtuple"; diff --git a/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestCreator.java b/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestCreator.java index d4b0c112b8fb..2e1c623cc568 100644 --- a/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestCreator.java +++ b/python/src/com/jetbrains/python/codeInsight/testIntegration/PyTestCreator.java @@ -80,7 +80,7 @@ public class PyTestCreator implements TestCreator { fileText.append("pass\n"); for (String method : methods) { - fileText.append("def ").append(method).append("(self):\n self.fail()\n\n\t"); + fileText.append("def ").append(method).append("(self):\n\tself.fail()\n\n\t"); } PsiFile psiFile = PyUtil.getOrCreateFile( diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index 6afa2ec73f5f..875480d5b0e8 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -25,6 +25,7 @@ import com.intellij.execution.Executor; import com.intellij.execution.configurations.EncodingEnvironmentUtil; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.ParamsGroup; +import com.intellij.execution.configurations.PtyCommandLine; import com.intellij.execution.console.ConsoleHistoryController; import com.intellij.execution.console.LanguageConsoleView; import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler; @@ -464,7 +465,8 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory ERROR_CODES_DESCRIPTION = ImmutableMap.builder() + .put("N801", "Class names should use CamelCase convention") + .put("N802", "Function name should be lowercase") + .put("N803", "Argument name should be lowercase") + .put("N806", "Variable in function should be lowercase") + .put("N811", "Constant variable imported as non constant") + .put("N812", "Lowercase variable imported as non lowercase") + .put("N813", "CamelCase variable imported as lowercase") + .put("N814", "CamelCase variable imported as constant") + .build(); public final List ignoredErrors = new ArrayList(); @@ -94,19 +107,6 @@ public class PyPep8NamingInspection extends PyInspection { } public class Visitor extends PyInspectionVisitor { - @SuppressWarnings("Duplicates") private final HashMap errorCodesDescription = new HashMap() { - { - put("N801", "Class names should use CamelCase convention"); - put("N802", "Function name should be lowercase"); - put("N803", "Argument name should be lowercase"); - put("N806", "Variable in function should be lowercase"); - put("N811", "Constant variable imported as non constant"); - put("N812", "Lowercase variable imported as non lowercase"); - put("N813", "CamelCase variable imported as lowercase"); - put("N814", "CamelCase variable imported as constant"); - } - }; - public Visitor(ProblemsHolder holder, LocalInspectionToolSession session) { super(holder, session); } @@ -145,9 +145,9 @@ public class PyPep8NamingInspection extends PyInspection { private void registerAndAddRenameAndIgnoreErrorQuickFixes(@Nullable final PsiElement node, @NotNull final String errorCode) { if (getHolder() != null && getHolder().isOnTheFly()) - registerProblem(node, errorCodesDescription.get(errorCode), new PyRenameElementQuickFix(), new IgnoreErrorFix(errorCode)); + registerProblem(node, ERROR_CODES_DESCRIPTION.get(errorCode), new PyRenameElementQuickFix(), new IgnoreErrorFix(errorCode)); else - registerProblem(node, errorCodesDescription.get(errorCode), new IgnoreErrorFix(errorCode)); + registerProblem(node, ERROR_CODES_DESCRIPTION.get(errorCode), new IgnoreErrorFix(errorCode)); } @Override @@ -172,7 +172,7 @@ public class PyPep8NamingInspection extends PyInspection { final String errorCode = "N802"; if (!ignoredErrors.contains(errorCode)) { quickFixes.add(new IgnoreErrorFix(errorCode)); - registerProblem(nameNode.getPsi(), errorCodesDescription.get(errorCode), + registerProblem(nameNode.getPsi(), ERROR_CODES_DESCRIPTION.get(errorCode), quickFixes.toArray(new LocalQuickFix[quickFixes.size()])); } } @@ -218,7 +218,7 @@ public class PyPep8NamingInspection extends PyInspection { } private boolean isContextManager(PyClass node) { - final String[] contextManagerFunctionNames = new String[] {"__enter__", "__exit__"}; + final String[] contextManagerFunctionNames = {PyNames.ENTER, PyNames.EXIT}; for (String name: contextManagerFunctionNames) { if (node.findMethodByName(name, false, myTypeEvalContext) == null) { return false; diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index 0d81dcf06fa5..065c9ae609f7 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -89,6 +89,7 @@ public abstract class PythonCommandLineState extends CommandLineState { private final AbstractPythonRunConfiguration myConfig; private Boolean myMultiprocessDebug = null; + private boolean myRunWithPty = PtyCommandLine.isEnabled(); public boolean isDebug() { return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunner().getRunnerId()); @@ -235,7 +236,7 @@ public abstract class PythonCommandLineState extends CommandLineState { } public GeneralCommandLine generateCommandLine() { - GeneralCommandLine commandLine = createPythonCommandLine(myConfig.getProject(), myConfig, isDebug()); + GeneralCommandLine commandLine = createPythonCommandLine(myConfig.getProject(), myConfig, isDebug(), myRunWithPty); buildCommandLineParameters(commandLine); @@ -245,8 +246,8 @@ public abstract class PythonCommandLineState extends CommandLineState { } @NotNull - public static GeneralCommandLine createPythonCommandLine(Project project, PythonRunParams config, boolean isDebug) { - GeneralCommandLine commandLine = generalCommandLine(); + public static GeneralCommandLine createPythonCommandLine(Project project, PythonRunParams config, boolean isDebug, boolean runWithPty) { + GeneralCommandLine commandLine = generalCommandLine(runWithPty); commandLine.withCharset(EncodingProjectManager.getInstance(project).getDefaultCharset()); @@ -259,8 +260,8 @@ public abstract class PythonCommandLineState extends CommandLineState { return commandLine; } - public static GeneralCommandLine generalCommandLine() { - return PtyCommandLine.isEnabled() ? new PtyCommandLine() : new GeneralCommandLine(); + private static GeneralCommandLine generalCommandLine(boolean runWithPty) { + return runWithPty ? new PtyCommandLine() : new GeneralCommandLine(); } /** @@ -526,6 +527,10 @@ public abstract class PythonCommandLineState extends CommandLineState { myMultiprocessDebug = multiprocessDebug; } + public void setRunWithPty(boolean runWithPty) { + myRunWithPty = runWithPty; + } + @NotNull protected UrlFilter createUrlFilter(ProcessHandler handler) { return new UrlFilter(); diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java index 103f2a0856ec..27185f3a94a8 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java +++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java @@ -61,6 +61,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt public PythonTestCommandLineStateBase(AbstractPythonRunConfiguration configuration, ExecutionEnvironment env) { super(configuration, env); myConfiguration = configuration; + setRunWithPty(false); } @Override diff --git a/resources-en/src/inspectionDescriptions/TrivialFunctionalExpressionUsage.html b/resources-en/src/inspectionDescriptions/TrivialFunctionalExpressionUsage.html new file mode 100644 index 000000000000..9a469b82930d --- /dev/null +++ b/resources-en/src/inspectionDescriptions/TrivialFunctionalExpressionUsage.html @@ -0,0 +1,5 @@ + + +This inspection reports method calls to abstract methods of functional interfaces, when qualifiers for the calls are functional expressions: lambdas or method references. + + \ No newline at end of file diff --git a/resources-en/src/inspectionDescriptions/TrivialMethodReference.html b/resources-en/src/inspectionDescriptions/TrivialMethodReference.html new file mode 100644 index 000000000000..b4674967606f --- /dev/null +++ b/resources-en/src/inspectionDescriptions/TrivialMethodReference.html @@ -0,0 +1,5 @@ + + +This inspection reports method references which point to the abstract methods of the same functional interface types and hence can be replaced with their qualifiers + + \ No newline at end of file diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index f82a80267692..19912187a3a9 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -726,6 +726,12 @@ + +