From 6f04bc4adbc21994ac82dcafda8b8668bd15cfb1 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Sun, 28 Sep 2014 17:37:39 +0400 Subject: [PATCH 01/78] IDEA-129567 Correctly set environment variables when executing svn commands under terminal --- .../configurations/PtyCommandLine.java | 23 +++++++++++-------- .../idea/svn/commandLine/CommandExecutor.java | 9 ++++++-- .../svn/commandLine/TerminalExecutor.java | 13 +++++++---- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java index 182d347de4c1..2b8cdd2a9884 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java @@ -42,15 +42,7 @@ public class PtyCommandLine extends GeneralCommandLine { protected Process startProcess(@NotNull List commands) throws IOException { if (SystemInfo.isUnix) { try { - Map env = Maps.newHashMap(); - setupEnvironment(env); - - if (isRedirectErrorStream()) { - LOG.error("Launching process with PTY and redirected error stream is unsupported yet"); - } - - File workDirectory = getWorkDirectory(); - return PtyProcess.exec(ArrayUtil.toStringArray(commands), env, workDirectory != null ? workDirectory.getPath() : null, true); + return startProcessWithPty(commands, true); } catch (Throwable e) { LOG.error("Couldn't run process with PTY", e); @@ -59,4 +51,17 @@ public class PtyCommandLine extends GeneralCommandLine { return super.startProcess(commands); } + + @NotNull + public Process startProcessWithPty(@NotNull List commands, boolean console) throws IOException { + Map env = Maps.newHashMap(); + setupEnvironment(env); + + if (isRedirectErrorStream()) { + LOG.error("Launching process with PTY and redirected error stream is unsupported yet"); + } + + File workDirectory = getWorkDirectory(); + return PtyProcess.exec(ArrayUtil.toStringArray(commands), env, workDirectory != null ? workDirectory.getPath() : null, console); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java index 0b484e41d1c5..cdca82de6966 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java @@ -57,7 +57,7 @@ public class CommandExecutor { private boolean myNeedsDestroy; private volatile String myDestroyReason; private volatile boolean myWasCancelled; - protected final GeneralCommandLine myCommandLine; + @NotNull protected final GeneralCommandLine myCommandLine; protected Process myProcess; protected SvnProcessHandler myHandler; private OutputStreamWriter myProcessWriter; @@ -82,7 +82,7 @@ public class CommandExecutor { myListeners.addListener(new CommandCancelTracker()); } myLock = new Object(); - myCommandLine = new GeneralCommandLine(); + myCommandLine = createCommandLine(); myCommandLine.setExePath(exePath); myCommandLine.setWorkDirectory(command.getWorkingDirectory()); if (command.getConfigDir() != null) { @@ -227,6 +227,11 @@ public class CommandExecutor { return myCommand.getParameters().contains("--xml"); } + @NotNull + protected GeneralCommandLine createCommandLine() { + return new GeneralCommandLine(); + } + @NotNull protected Process createProcess() throws ExecutionException { return myCommandLine.createProcess(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java index 3409c7f52333..63fa3bbc0700 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalExecutor.java @@ -17,10 +17,10 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.execution.CommandLineUtil; import com.intellij.execution.ExecutionException; +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.execution.configurations.PtyCommandLine; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; -import com.pty4j.PtyProcess; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -81,6 +81,12 @@ public class TerminalExecutor extends CommandExecutor { return result; } + @NotNull + @Override + protected GeneralCommandLine createCommandLine() { + return new PtyCommandLine(); + } + @NotNull @Override protected Process createProcess() throws ExecutionException { @@ -97,8 +103,7 @@ public class TerminalExecutor extends CommandExecutor { @NotNull protected Process createProcess(@NotNull List parameters) throws ExecutionException { try { - return PtyProcess.exec(ArrayUtil.toStringArray(parameters), myCommandLine.getEnvironment(), - myCommandLine.getWorkDirectory().getAbsolutePath()); + return ((PtyCommandLine)myCommandLine).startProcessWithPty(parameters, false); } catch (IOException e) { throw new ExecutionException(e); From a1b4bb070dc78e5e3f3392e25c971ef253b304be Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 01:21:44 +0400 Subject: [PATCH 02/78] svn: terminal: Refactored TerminalSshModule - extracted common terminal-related logic to BaseTerminalModule --- .../svn/commandLine/BaseTerminalModule.java | 56 +++++++++++++++++++ .../svn/commandLine/TerminalSshModule.java | 34 ++--------- 2 files changed, 61 insertions(+), 29 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java new file mode 100644 index 000000000000..a8f60d4fb325 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NotNull; + +/** + * @author Konstantin Kolosovsky. + */ +public abstract class BaseTerminalModule extends LineCommandAdapter implements CommandRuntimeModule, InteractiveCommandListener { + + private static final Logger LOG = Logger.getInstance(BaseTerminalModule.class); + + @NotNull protected final CommandRuntime myRuntime; + @NotNull protected final CommandExecutor myExecutor; + + // TODO: Do not accept executor here and make it as command runtime module + protected BaseTerminalModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) { + myRuntime = runtime; + myExecutor = executor; + } + + @Override + public void onStart(@NotNull Command command) throws SvnBindException { + } + + protected boolean sendData(@NotNull String data) { + try { + myExecutor.write(data + "\n"); + return true; + } + catch (SvnBindException e) { + // TODO: handle this more carefully + LOG.info(e); + } + return false; + } + + protected void cancelAuthentication() { + myExecutor.destroyProcess("Authentication canceled for repository: " + myExecutor.getCommand().getRepositoryUrl()); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java index ca4fce9d910b..21fd574d31bb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java @@ -16,7 +16,6 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; @@ -34,9 +33,7 @@ import java.util.regex.Pattern; /** * @author Konstantin Kolosovsky. */ -public class TerminalSshModule extends LineCommandAdapter implements CommandRuntimeModule, InteractiveCommandListener { - - private static final Logger LOG = Logger.getInstance(TerminalSshModule.class); +public class TerminalSshModule extends BaseTerminalModule { private static final Pattern PASSPHRASE_PROMPT = Pattern.compile("Enter passphrase for key \\'(.*)\\':\\s?"); private static final Pattern PASSWORD_PROMPT = Pattern.compile("(.*)\\'s password:\\s?"); @@ -46,21 +43,12 @@ public class TerminalSshModule extends LineCommandAdapter implements CommandRunt private static final Pattern HOST_FINGERPRINT_MESSAGE = Pattern.compile("(\\w+) key fingerprint is (.*)\\.\\s?"); private static final Pattern ACCEPT_HOST_PROMPT = Pattern.compile("Are you sure you want to continue connecting \\(yes/no\\)\\?\\s?"); - @NotNull private final CommandRuntime myRuntime; - @NotNull private final CommandExecutor myExecutor; - private String unknownHost; private String fingerprintAlgorithm; private String hostFingerprint; - // TODO: Do not accept executor here and make it as command runtime module public TerminalSshModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) { - myExecutor = executor; - myRuntime = runtime; - } - - @Override - public void onStart(@NotNull Command command) throws SvnBindException { + super(runtime, executor); } @Override @@ -120,7 +108,7 @@ public class TerminalSshModule extends LineCommandAdapter implements CommandRunt fingerprintAlgorithm = null; hostFingerprint = null; - sendAnswer(answer.get() == ISVNAuthenticationProvider.REJECTED ? "no" : "yes"); + sendData(answer.get() == ISVNAuthenticationProvider.REJECTED ? "no" : "yes"); } private boolean handleAuthPrompt(@NotNull final SimpleCredentialsDialog.Mode mode, @NotNull final String key) { @@ -133,23 +121,11 @@ public class TerminalSshModule extends LineCommandAdapter implements CommandRunt myRuntime.getAuthenticationService().requestSshCredentials(repositoryUrl != null ? repositoryUrl.toDecodedString() : "", mode, key); if (!StringUtil.isEmpty(auth)) { - sendAnswer(auth); + sendData(auth); } else { - myExecutor.destroyProcess("Authentication canceled for repository: " + repositoryUrl); + cancelAuthentication(); } return !StringUtil.isEmpty(auth); } - - private boolean sendAnswer(@NotNull String answer) { - try { - myExecutor.write(answer + "\n"); - return true; - } - catch (SvnBindException e) { - // TODO: handle this more carefully - LOG.info(e); - } - return false; - } } From cfa0be2a75a1884f15ac9f8cabdd721ae37d88ea Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 01:36:13 +0400 Subject: [PATCH 03/78] svn: terminal: Use "\r\n" as line end when sending data to svn command line client - both "\n" and "\r\n" work for Unix, but for Windows svn client does not continue execution (in all cases) if line end is "\n" (for instance, when sending responses to username/password prompts) --- .../org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java index a8f60d4fb325..062a6be7c119 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.LineSeparator; import org.jetbrains.annotations.NotNull; /** @@ -40,7 +41,7 @@ public abstract class BaseTerminalModule extends LineCommandAdapter implements C protected boolean sendData(@NotNull String data) { try { - myExecutor.write(data + "\n"); + myExecutor.write(data + LineSeparator.CRLF.getSeparatorString()); return true; } catch (SvnBindException e) { From 232bd007b9095dc154f24253d70e3721c06ed212 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 01:57:04 +0400 Subject: [PATCH 04/78] svn: terminal: Skip (treat as handled prompt - do not treat as error) next received line after sending data to svn command line client (if this line is not explicitly detected as prompt to handle) - as this next line will just contain sent answer (and no new data) --- .../svn/commandLine/BaseTerminalModule.java | 28 +++++++++++++++++++ .../svn/commandLine/TerminalSshModule.java | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java index 062a6be7c119..d4b9475ee5d5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Key; import com.intellij.util.LineSeparator; import org.jetbrains.annotations.NotNull; @@ -29,6 +30,8 @@ public abstract class BaseTerminalModule extends LineCommandAdapter implements C @NotNull protected final CommandRuntime myRuntime; @NotNull protected final CommandExecutor myExecutor; + protected boolean mySkipOneLine; + // TODO: Do not accept executor here and make it as command runtime module protected BaseTerminalModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) { myRuntime = runtime; @@ -39,8 +42,33 @@ public abstract class BaseTerminalModule extends LineCommandAdapter implements C public void onStart(@NotNull Command command) throws SvnBindException { } + /** + * When we send data to svn - we then get it back from corresponding stream. We could receive, for example: + * - just sent data - for http, https in Unix + * - prompt line + sent data (at the end) - for http, https in Windows + * - just new line - for ssh client (as ssh does not output sent data to console) + *

+ * That is why if the next line (after answer is sent) is not explicitly handled, we skip it anyway. + */ + @Override + public boolean handlePrompt(String line, Key outputType) { + boolean result = doHandlePrompt(line, outputType); + + if (!result && mySkipOneLine) { + LOG.debug("Skipped " + outputType + " line: " + line); + + mySkipOneLine = false; + result = true; + } + + return result; + } + + protected abstract boolean doHandlePrompt(String line, Key outputType); + protected boolean sendData(@NotNull String data) { try { + mySkipOneLine = true; myExecutor.write(data + LineSeparator.CRLF.getSeparatorString()); return true; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java index 21fd574d31bb..1ebd86485033 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java @@ -52,7 +52,7 @@ public class TerminalSshModule extends BaseTerminalModule { } @Override - public boolean handlePrompt(String line, Key outputType) { + public boolean doHandlePrompt(String line, Key outputType) { return checkPassphrase(line) || checkPassword(line) || checkUnknownHost(line); } From cb21e8be79499af411b95c4f02a43fb7f03f896b Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 12:19:45 +0400 Subject: [PATCH 05/78] svn: terminal: Only check error stream (or single process stream if process does not have separate output and error streams) when handling svn command line client prompts --- .../commandLine/TerminalProcessHandler.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java index 1bd8a2e44fad..4e22575c7444 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalProcessHandler.java @@ -71,17 +71,30 @@ public class TerminalProcessHandler extends SvnProcessHandler { currentLine = filterCombinedText(currentLine); // check if current line presents some interactive output - boolean handled = false; - for (InteractiveCommandListener listener : myInteractiveListeners) { - handled |= listener.handlePrompt(currentLine, outputType); - } - + boolean handled = handlePrompt(currentLine, outputType); if (!handled) { notify(currentLine, outputType, lastLine); } } } + protected boolean handlePrompt(String text, Key outputType) { + // if process has separate output and error streams => try to handle prompts only from error stream output + boolean shouldHandleWithListeners = !processHasSeparateErrorStream() || ProcessOutputTypes.STDERR.equals(outputType); + + return shouldHandleWithListeners && handlePromptWithListeners(text, outputType); + } + + private boolean handlePromptWithListeners(String text, Key outputType) { + boolean result = false; + + for (InteractiveCommandListener listener : myInteractiveListeners) { + result |= listener.handlePrompt(text, outputType); + } + + return result; + } + @NotNull protected String filterCombinedText(@NotNull String currentLine) { return currentLine; From 4d86643acaa00aa8344f6ca5895014c08a286d26 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 12:28:40 +0400 Subject: [PATCH 06/78] svn: Treat svn command line client error stream content as warning (in case of successful command execution) only if it contains some non-whitespace characters --- .../jetbrains/idea/svn/commandLine/CommandRuntime.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index a22ec9b3fed3..3b4aa9aa4605 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -23,7 +23,10 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.SvnApplicationSettings; +import org.jetbrains.idea.svn.SvnProgressCanceller; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.auth.AuthenticationService; import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; import org.tmatesoft.svn.core.SVNURL; @@ -99,10 +102,10 @@ public class CommandRuntime { return repeat; } - private static void handleSuccess(CommandExecutor executor) { + private static void handleSuccess(@NotNull CommandExecutor executor) { // could be situations when exit code = 0, but there is info "warning" in error stream for instance, for "svn status" // on non-working copy folder - if (executor.getErrorOutput().length() > 0) { + if (!StringUtil.isEmptyOrSpaces(executor.getErrorOutput())) { // here exitCode == 0, but some warnings are in error stream LOG.info("Detected warning - " + executor.getErrorOutput()); } From e17b65da1f0243494d16663b6c56650ea92d5318 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 13:09:38 +0400 Subject: [PATCH 07/78] svn: Always show authentication dialogs (if requested) for different modality/progress cases - use ModalityState.any() if progress indicator is null --- .../SvnInteractiveAuthenticationProvider.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java index de2c007b7879..83c992f5799e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java @@ -16,9 +16,8 @@ package org.jetbrains.idea.svn.auth; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.MessageType; @@ -40,9 +39,7 @@ import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.*; import org.tmatesoft.svn.core.internal.wc.ISVNHostOptions; -import javax.swing.*; import java.io.File; -import java.lang.reflect.InvocationTargetException; import java.security.cert.X509Certificate; public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationProvider { @@ -170,7 +167,7 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP } if (command != null) { - WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command); + showAndWait(command); log("3 authentication result: " + result[0]); } @@ -227,23 +224,15 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP MessageType.ERROR); return REJECTED; } - final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator(); - if (pi != null) { - WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, pi.getModalityState()); - } else { - try { - SwingUtilities.invokeAndWait(command); - } - catch (InterruptedException e) { - // - } - catch (InvocationTargetException e) { - // - } - } + + showAndWait(command); return result[0]; } + private static void showAndWait(@NotNull Runnable command) { + WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any()); + } + private void log(final String s) { LOG.debug(s); } From ef00ee9cfd73a50931656025077578d911e5abc2 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 13:14:00 +0400 Subject: [PATCH 08/78] svn: Allow executing commands under terminal (if configured) for all svn repository protocols (and not only for "svn+ssh") --- .../jetbrains/idea/svn/commandLine/CommandRuntime.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index 3b4aa9aa4605..2d15ccbc029d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -28,7 +28,6 @@ import org.jetbrains.idea.svn.SvnProgressCanceller; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.auth.AuthenticationService; -import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; import org.tmatesoft.svn.core.SVNURL; import java.io.File; @@ -205,7 +204,7 @@ public class CommandRuntime { private CommandExecutor newExecutor(@NotNull Command command) { final CommandExecutor executor; - if (!(Registry.is("svn.use.terminal") && isForSshRepository(command)) || isLocal(command)) { + if (!Registry.is("svn.use.terminal") || isLocal(command)) { command.putIfNotPresent("--non-interactive"); executor = new CommandExecutor(exePath, command); } @@ -237,12 +236,6 @@ public class CommandRuntime { command.isLocalInfo() || command.isLocalStatus() || command.isLocalProperty() || command.isLocalCat(); } - private static boolean isForSshRepository(@NotNull Command command) { - SVNURL url = command.getRepositoryUrl(); - - return url != null && StringUtil.equalsIgnoreCase(SvnAuthenticationManager.SVN_SSH, url.getProtocol()); - } - @NotNull public AuthenticationService getAuthenticationService() { return myAuthenticationService; From ef20fa792ff7bea243e2fd7b6140f12beee84b5d Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 13:45:59 +0400 Subject: [PATCH 09/78] svn: terminal: Implemented handling of user name, password prompts (used for http, https, svn repository protocols) when running svn under terminal --- .../idea/svn/commandLine/CommandRuntime.java | 1 + .../TerminalUserNamePasswordModule.java | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index 2d15ccbc029d..e0d4884c0afd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -213,6 +213,7 @@ public class CommandRuntime { // running under terminal executor = newTerminalExecutor(command); ((TerminalExecutor)executor).addInteractiveListener(new TerminalSshModule(this, executor)); + ((TerminalExecutor)executor).addInteractiveListener(new TerminalUserNamePasswordModule(this, executor)); } return executor; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java new file mode 100644 index 000000000000..dbb1d211a8b4 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; +import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Konstantin Kolosovsky. + */ +public class TerminalUserNamePasswordModule extends BaseTerminalModule { + + private static final Pattern USER_NAME_PROMPT = Pattern.compile("Username:\\s?"); + private static final Pattern PASSWORD_PROMPT = Pattern.compile("Password for \\'(.*)\\':\\s?"); + + private static final Pattern AUTHENTICATION_REALM_MESSAGE = Pattern.compile("Authentication realm: (.*)\\s?"); + + private String realm; + private String userName; + private SVNPasswordAuthentication authentication; + + public TerminalUserNamePasswordModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) { + super(runtime, executor); + } + + @Override + public boolean doHandlePrompt(String line, Key outputType) { + return checkRealm(line) || checkUserName(line) || checkPassword(line); + } + + private boolean checkRealm(@NotNull String line) { + Matcher matcher = AUTHENTICATION_REALM_MESSAGE.matcher(line); + + if (matcher.matches()) { + realm = matcher.group(1); + } + + return matcher.matches(); + } + + private boolean checkUserName(@NotNull String line) { + Matcher matcher = USER_NAME_PROMPT.matcher(line); + + return matcher.matches() && handleAuthPrompt(true); + } + + private boolean checkPassword(@NotNull String line) { + Matcher matcher = PASSWORD_PROMPT.matcher(line); + + if (matcher.matches()) { + userName = matcher.group(1); + } + + return matcher.matches() && handleAuthPrompt(false); + } + + /** + * User name and password are asked separately by svn, but we show single dialog for both parameters. Also password could be asked first + * (before any user name prompt) for pre-configured/system user name. + */ + private boolean handleAuthPrompt(boolean isUserName) { + // TODO: check command is not local and get @NotNull url - also make same for for ssh module + SVNURL repositoryUrl = myExecutor.getCommand().getRepositoryUrl(); + + if (needAskAuthentication(isUserName)) { + // TODO: Probably pass real realm to dialog + // TODO: Extend interface to pass username to dialog (probably using some kind of previousAuth, like in SVNKit) + authentication = (SVNPasswordAuthentication)myRuntime.getAuthenticationService() + .requestCredentials(repositoryUrl, ISVNAuthenticationManager.PASSWORD); + } + + return sendData(isUserName); + } + + private boolean needAskAuthentication(boolean isUserName) { + // "authentication.getUserName()" was provided by user, "userName" was asked by svn. If they are equal but svn still prompts user name - + // we treat this as "authentication" credentials are incorrect and we need ask user again. + return authentication == null || isUserName && StringUtil.equals(userName, authentication.getUserName()); + } + + private boolean sendData(boolean isUserName) { + if (authentication != null) { + sendData(isUserName ? authentication.getUserName() : authentication.getPassword()); + } + else { + cancelAuthentication(); + } + + return authentication != null; + } +} From 988509635cd754adfa5d90cd91f1f4d33e0e373e Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 14:08:18 +0400 Subject: [PATCH 10/78] svn: Refactored ServerSSLDialog - code simplified, warnings fixed, @NotNull --- .../idea/svn/dialogs/ServerSSLDialog.java | 72 +++++++++---------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java index fc6bb33c4db3..51656f466909 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java @@ -22,11 +22,12 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider; +import org.tmatesoft.svn.core.internal.util.SVNSSLUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; -import java.security.MessageDigest; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; /** @@ -34,12 +35,12 @@ import java.security.cert.X509Certificate; */ public class ServerSSLDialog extends DialogWrapper { - private final X509Certificate myCertificate; + @NotNull private final X509Certificate myCertificate; private Action myTempAction; private int myResult; @NonNls public static final String ALGORITHM_SHA1 = "SHA1"; - public ServerSSLDialog(final Project project, X509Certificate cert, boolean store) { + public ServerSSLDialog(final Project project, @NotNull X509Certificate cert, boolean store) { super(project, true); myCertificate = cert; myResult = ISVNAuthenticationProvider.REJECTED; @@ -101,43 +102,34 @@ public class ServerSSLDialog extends DialogWrapper { return panel; } - private static String getFingerprint(X509Certificate cert) { - StringBuffer s = new StringBuffer(); - try { - MessageDigest md = MessageDigest.getInstance(ALGORITHM_SHA1); - md.update(cert.getEncoded()); - byte[] digest = md.digest(); - for (int i= 0; i < digest.length; i++) { - if (i != 0) { - s.append(':'); - } - int b = digest[i] & 0xFF; - String hex = Integer.toHexString(b); - if (hex.length() == 1) { - s.append('0'); - } - s.append(hex.toLowerCase()); - } - } catch (Exception e) { - // - } - return s.toString(); - } + @NotNull + private static String getFingerprint(@NotNull X509Certificate cert) { + byte[] data = null; - @SuppressWarnings({"HardCodedStringLiteral"}) - private static String getServerCertificateInfo(X509Certificate cert) { - StringBuffer info = new StringBuffer(); - info.append(" - Subject: "); - info.append(cert.getSubjectDN().getName()); - info.append('\n'); - info.append(" - Valid: "); - info.append("from ").append(cert.getNotBefore()).append(" until ").append(cert.getNotAfter()); - info.append('\n'); - info.append(" - Issuer: "); - info.append(cert.getIssuerDN().getName()); - info.append('\n'); - info.append(" - Fingerprint: "); - info.append(getFingerprint(cert)); - return info.toString(); + try { + data = cert.getEncoded(); + } + catch (CertificateEncodingException ignore) { + } + + return data != null ? SVNSSLUtil.getFingerprint(data, ALGORITHM_SHA1) : ""; + } + + @SuppressWarnings({"HardCodedStringLiteral", "StringBufferReplaceableByString"}) + @NotNull + private static String getServerCertificateInfo(@NotNull X509Certificate cert) { + return new StringBuilder() + .append(" - Subject: ") + .append(cert.getSubjectDN().getName()) + .append('\n') + .append(" - Valid: ") + .append("from ").append(cert.getNotBefore()).append(" until ").append(cert.getNotAfter()) + .append('\n') + .append(" - Issuer: ") + .append(cert.getIssuerDN().getName()) + .append('\n') + .append(" - Fingerprint: ") + .append(getFingerprint(cert)) + .toString(); } } From e59761610006f0288e605b0a32122009736434f1 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 14:28:44 +0400 Subject: [PATCH 11/78] svn: terminal: Implemented handling of "accept server certificate" prompt (used for https repository protocol) when running svn under terminal --- .../jetbrains/idea/svn/auth/AcceptResult.java | 51 ++++++++ .../idea/svn/auth/AuthenticationService.java | 23 ++++ .../SvnInteractiveAuthenticationProvider.java | 6 +- .../idea/svn/commandLine/CommandRuntime.java | 1 + .../TerminalSslCertificateModule.java | 112 ++++++++++++++++++ .../idea/svn/dialogs/ServerSSLDialog.java | 10 +- 6 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AcceptResult.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSslCertificateModule.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AcceptResult.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AcceptResult.java new file mode 100644 index 000000000000..004d47c5ac04 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AcceptResult.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.auth; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Konstantin Kolosovsky. + */ +public enum AcceptResult { + + REJECTED("r"), + ACCEPTED_TEMPORARILY("t"), + ACCEPTED_PERMANENTLY("p"); + + // cache all values as values() method returns new array on each call + private static final AcceptResult[] allValues = values(); + + @NotNull private final String code; + + AcceptResult(@NotNull String code) { + this.code = code; + } + + @Override + public String toString() { + return code; + } + + @NotNull + public static AcceptResult from(int value) { + if (value < 0 || value >= allValues.length) { + throw new IllegalArgumentException("Unknown AcceptResult - " + value); + } + + return allValues[value]; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java index a8a0d7ccdc60..cadd6088eb76 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java @@ -181,6 +181,29 @@ public class AuthenticationService { }); } + @NotNull + public AcceptResult acceptCertificate(@NotNull final SVNURL url, @NotNull final String certificateInfo) { + // TODO: Probably explicitly construct server url for realm here - like in CertificateTrustManager. + String kind = "svn.ssl.server"; + String realm = url.toDecodedString(); + Object data = SvnConfiguration.RUNTIME_AUTH_CACHE.getDataWithLowerCheck(kind, realm); + AcceptResult result; + + if (data != null) { + result = (AcceptResult)data; + } + else { + result = + AcceptResult.from(getAuthenticationManager().getInnerProvider().acceptServerAuthentication(url, realm, certificateInfo, true)); + + if (!AcceptResult.REJECTED.equals(result)) { + myVcs.getSvnConfiguration().acknowledge(kind, realm, result); + } + } + + return result; + } + public boolean acceptSSLServerCertificate(@Nullable SVNURL repositoryUrl, final String realm) throws SvnBindException { if (repositoryUrl == null) { return false; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java index 83c992f5799e..8f7ff15d4944 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnInteractiveAuthenticationProvider.java @@ -200,10 +200,12 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP public int acceptServerAuthentication(final SVNURL url, String realm, final Object certificate, final boolean resultMayBeStored) { final int[] result = new int[1]; Runnable command; - if (certificate instanceof X509Certificate) { + if (certificate instanceof X509Certificate || certificate instanceof String) { command = new Runnable() { public void run() { - ServerSSLDialog dialog = new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored); + ServerSSLDialog dialog = certificate instanceof X509Certificate + ? new ServerSSLDialog(myProject, (X509Certificate)certificate, resultMayBeStored) + : new ServerSSLDialog(myProject, (String)certificate, resultMayBeStored); dialog.show(); result[0] = dialog.getResult(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index e0d4884c0afd..2a2cf062a039 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -213,6 +213,7 @@ public class CommandRuntime { // running under terminal executor = newTerminalExecutor(command); ((TerminalExecutor)executor).addInteractiveListener(new TerminalSshModule(this, executor)); + ((TerminalExecutor)executor).addInteractiveListener(new TerminalSslCertificateModule(this, executor)); ((TerminalExecutor)executor).addInteractiveListener(new TerminalUserNamePasswordModule(this, executor)); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSslCertificateModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSslCertificateModule.java new file mode 100644 index 000000000000..64a23f1c574e --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSslCertificateModule.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.svn.commandLine; + +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.auth.AcceptResult; +import org.tmatesoft.svn.core.SVNURL; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Allows responding to "accept certificate" prompts of the following structure: + *

+ * Error validating server certificate for '%server_url%': + * %certificate_error% + * Certificate information: + * %certificate_info% + * (R)eject, accept (t)emporarily or accept (p)ermanently? + * + * @author Konstantin Kolosovsky. + */ +public class TerminalSslCertificateModule extends BaseTerminalModule { + + private static final Pattern ERROR_VALIDATING_CERTIFICATE_MESSAGE = + Pattern.compile("Error validating server certificate for \\'(.*)\\':\\s?"); + private static final Pattern CERTIFICATE_INFORMATION_MESSAGE = Pattern.compile("Certificate information:\\s?"); + // messages could be either "(R)eject or accept (t)emporarily?" or "(R)eject, accept (t)emporarily or accept (p)ermanently?" depending on + // if credentials caching is allowed + private static final Pattern ACCEPT_CERTIFICATE_PROMPT = Pattern.compile("\\(R\\)eject.*\\?\\s?"); + + @NotNull private final StringBuilder certificateError = new StringBuilder(); + @NotNull private final StringBuilder certificateInfo = new StringBuilder(); + private boolean collectingCertificateError; + private boolean collectingCertificateInfo; + private String serverUrl; + + public TerminalSslCertificateModule(@NotNull CommandRuntime runtime, @NotNull CommandExecutor executor) { + super(runtime, executor); + } + + @Override + public boolean doHandlePrompt(String line, Key outputType) { + return checkCertificate(line); + } + + private boolean checkCertificate(String line) { + Matcher certificateErrorMatcher = ERROR_VALIDATING_CERTIFICATE_MESSAGE.matcher(line); + Matcher certificateInfoMatcher = CERTIFICATE_INFORMATION_MESSAGE.matcher(line); + Matcher acceptCertificateMatcher = ACCEPT_CERTIFICATE_PROMPT.matcher(line); + + if (certificateErrorMatcher.matches()) { + serverUrl = certificateErrorMatcher.group(1); + setCollectingMode(false, true); + } + else if (certificateInfoMatcher.matches()) { + setCollectingMode(true, false); + } + else if (acceptCertificateMatcher.matches()) { + setCollectingMode(false, false); + handleAcceptCertificatePrompt(); + } + else if (collectingCertificateError) { + certificateError.append(line); + } + else if (collectingCertificateInfo) { + certificateInfo.append(line); + } + + return certificateErrorMatcher.matches() || + certificateInfoMatcher.matches() || + acceptCertificateMatcher.matches() || + collectingCertificateError || + collectingCertificateInfo; + } + + private void setCollectingMode(boolean collectInfo, boolean collectError) { + collectingCertificateInfo = collectInfo; + collectingCertificateError = collectError; + + if (collectingCertificateInfo) { + certificateInfo.setLength(0); + } + + if (collectingCertificateError) { + certificateError.setLength(0); + } + } + + private void handleAcceptCertificatePrompt() { + // TODO: show 'certificateError' in dialog + SVNURL url = SvnUtil.parseUrl(serverUrl); + AcceptResult result = myRuntime.getAuthenticationService().acceptCertificate(url, certificateInfo.toString()); + + sendData(result.toString()); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java index 51656f466909..5713f9b62106 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/ServerSSLDialog.java @@ -35,14 +35,18 @@ import java.security.cert.X509Certificate; */ public class ServerSSLDialog extends DialogWrapper { - @NotNull private final X509Certificate myCertificate; + @NotNull private final String myCertificateInfo; private Action myTempAction; private int myResult; @NonNls public static final String ALGORITHM_SHA1 = "SHA1"; public ServerSSLDialog(final Project project, @NotNull X509Certificate cert, boolean store) { + this(project, getServerCertificateInfo(cert), store); + } + + public ServerSSLDialog(final Project project, @NotNull String certificateInfo, boolean store) { super(project, true); - myCertificate = cert; + myCertificateInfo = certificateInfo; myResult = ISVNAuthenticationProvider.REJECTED; setOKButtonText(SvnBundle.message("button.text.ssl.accept")); setOKActionEnabled(store); @@ -95,7 +99,7 @@ public class ServerSSLDialog extends DialogWrapper { JPanel panel = new JPanel(new BorderLayout(5,5)); panel.add(new JLabel(SvnBundle.message("label.ssl.server.provided.certificate")), BorderLayout.NORTH); JTextArea area = new JTextArea(5, 50); - area.setText(getServerCertificateInfo(myCertificate)); + area.setText(myCertificateInfo); area.setEditable(false); panel.add(ScrollPaneFactory.createScrollPane(area), BorderLayout.CENTER); From 5c9149d70f24e2420379c40e3c179d66710ca683 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 29 Sep 2014 16:39:12 +0400 Subject: [PATCH 12/78] svn: terminal: Added "Run under terminal" option to Subversion settings to control if svn command line client should run under terminal (instead of "svn.use.terminal" registry key) --- .../util/resources/misc/registry.properties | 1 - .../jetbrains/idea/svn/SvnConfigurable.form | 21 +++++++++++++------ .../jetbrains/idea/svn/SvnConfigurable.java | 11 ++++++++++ .../jetbrains/idea/svn/SvnConfiguration.java | 8 +++++++ .../idea/svn/SvnConfigurationState.java | 2 ++ .../idea/svn/commandLine/CommandRuntime.java | 3 +-- 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 53628fcec0ce..1f09676c88a2 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -337,7 +337,6 @@ search.everywhere.actions=true search.everywhere.configurations=true search.everywhere.settings=false -svn.use.terminal=false svn.use.incoming.optimization=false svn.executable.locale=C.UTF-8 svn.lowest.supported.format.for.command.line=1.7.0 diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form index 55f7512fbb81..af83a0c367a1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -123,12 +123,12 @@ - + - + @@ -156,6 +156,15 @@ + + + + + + + + + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java index 63706ee1e1f1..9a7af5cb4c40 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java @@ -65,6 +65,7 @@ public class SvnConfigurable implements Configurable { private JCheckBox myIgnoreWhitespaceDifferenciesInCheckBox; private JCheckBox myShowMergeSourceInAnnotate; private JBCheckBox myWithCommandLineClient; + private JBCheckBox myRunUnderTerminal; private JSpinner myNumRevsInAnnotations; private JCheckBox myMaximumNumberOfRevisionsCheckBox; private JSpinner mySSHConnectionTimeout; @@ -81,6 +82,12 @@ public class SvnConfigurable implements Configurable { public SvnConfigurable(Project project) { myProject = project; + myWithCommandLineClient.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + myRunUnderTerminal.setEnabled(myWithCommandLineClient.isSelected()); + } + }); myUseDefaultCheckBox.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { boolean enabled = !myUseDefaultCheckBox.isSelected(); @@ -228,6 +235,7 @@ public class SvnConfigurable implements Configurable { return true; } if (! configuration.getUseAcceleration().equals(acceleration())) return true; + if (configuration.isRunUnderTerminal() != myRunUnderTerminal.isSelected()) return true; final int annotateRevisions = configuration.getMaxAnnotateRevisions(); final boolean useMaxInAnnot = annotateRevisions != -1; if (useMaxInAnnot != myMaximumNumberOfRevisionsCheckBox.isSelected()) { @@ -280,6 +288,7 @@ public class SvnConfigurable implements Configurable { boolean reloadWorkingCopies = !acceleration().equals(configuration.getUseAcceleration()) || !StringUtil.equals(applicationSettings17.getCommandLinePath(), myCommandLineClient.getText().trim()); configuration.setUseAcceleration(acceleration()); + configuration.setRunUnderTerminal(myRunUnderTerminal.isSelected()); configuration.setSslProtocols(getSelectedSSL()); SvnVcs.getInstance(myProject).getSvnKitManager().refreshSSLProperty(); @@ -324,6 +333,8 @@ public class SvnConfigurable implements Configurable { mySSHReadTimeout.setValue(Long.valueOf(configuration.getSshReadTimeout() / 1000)); myHttpTimeout.setValue(Long.valueOf(configuration.getHttpTimeout() / 1000)); myWithCommandLineClient.setSelected(configuration.isCommandLine()); + myRunUnderTerminal.setSelected(configuration.isRunUnderTerminal()); + myRunUnderTerminal.setEnabled(myWithCommandLineClient.isSelected()); final SvnApplicationSettings applicationSettings17 = SvnApplicationSettings.getInstance(); myCommandLineClient.setText(applicationSettings17.getCommandLinePath()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java index bbafc719f43b..0448a9723e89 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java @@ -190,6 +190,14 @@ public class SvnConfiguration implements PersistentStateComponent Date: Mon, 29 Sep 2014 17:56:49 +0400 Subject: [PATCH 13/78] fixed task file wrong invalidation --- .../src/com/jetbrains/python/edu/StudyDocumentListener.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java index 5bbd4d681cb3..a12e38738f72 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java @@ -113,9 +113,6 @@ public class StudyDocumentListener extends DocumentAdapter { if (myTaskWindow != null) { int newLength = myTaskWindow.getLength() + change; myTaskWindow.setLength(newLength <= 0 ? 0 : newLength); - if (e.getNewFragment().equals("\n")) { - myTaskWindow.setLength(myTaskWindow.getLength() + 1); - } } int newEnd = offset + event.getNewLength(); int newLine = document.getLineNumber(newEnd); From 2a6eafd217323dbf2aa033e18d5164f8f0b5083c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Sep 2014 15:08:24 +0200 Subject: [PATCH 14/78] do not mark Plugins modified if plugin was disabled on startup due to incompatibility changes (IDEA-114768) --- .../ide/plugins/InstalledPluginsManagerMain.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsManagerMain.java index cd108befbe1a..0bab1797b8e0 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsManagerMain.java @@ -318,9 +318,15 @@ public class InstalledPluginsManagerMain extends PluginManagerMain { public boolean isModified() { final boolean modified = super.isModified(); if (modified) return true; + final List disabledPlugins = PluginManagerCore.getDisabledPlugins(); for (int i = 0; i < pluginsModel.getRowCount(); i++) { final IdeaPluginDescriptor pluginDescriptor = pluginsModel.getObjectAt(i); - if (pluginDescriptor.isEnabled() != ((InstalledPluginsTableModel)pluginsModel).isEnabled(pluginDescriptor.getPluginId())) { + final PluginId pluginId = pluginDescriptor.getPluginId(); + final boolean enabledInTable = ((InstalledPluginsTableModel)pluginsModel).isEnabled(pluginId); + if (pluginDescriptor.isEnabled() != enabledInTable) { + if (enabledInTable && !disabledPlugins.contains(pluginId.getIdString())) { + continue; //was disabled automatically on startup + } return true; } } @@ -330,7 +336,6 @@ public class InstalledPluginsManagerMain extends PluginManagerMain { return true; } } - final List disabledPlugins = PluginManagerCore.getDisabledPlugins(); for (Map.Entry entry : ((InstalledPluginsTableModel)pluginsModel).getEnabledMap().entrySet()) { final Boolean enabled = entry.getValue(); if (enabled != null && !enabled.booleanValue() && !disabledPlugins.contains(entry.getKey().toString())) { From 3723032df77dd0d04fd834d8d932e81e136c403d Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Sep 2014 15:29:49 +0200 Subject: [PATCH 15/78] restore old module patterns (IDEA-130308) --- .../packageSet/FilePatternPackageSet.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java index db0c71b9f99a..d383ffb31466 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java +++ b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java @@ -33,6 +33,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.util.regex.Pattern; @@ -56,12 +57,12 @@ public class FilePatternPackageSet extends PatternBasedPackageSet { if (modulePattern.startsWith("group:")) { int idx = modulePattern.indexOf(':', 6); if (idx == -1) idx = modulePattern.length(); - myModuleGroupPattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(6, idx))); + myModuleGroupPattern = Pattern.compile(StringUtil.replace(escapeToRegexp(modulePattern.substring(6, idx)), "*", ".*")); if (idx < modulePattern.length() - 1) { - myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(idx + 1))); + myModulePattern = Pattern.compile(StringUtil.replace(escapeToRegexp(modulePattern.substring(idx + 1)), "*", ".*")); } } else { - myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern)); + myModulePattern = Pattern.compile(StringUtil.replace(escapeToRegexp(modulePattern), "*", ".*")); } } myFilePattern = filePattern != null ? Pattern.compile(convertToRegexp(filePattern, '/')) : null; @@ -109,10 +110,25 @@ public class FilePatternPackageSet extends PatternBasedPackageSet { return modulePattern == null && moduleGroupPattern == null; } + @NotNull + private static String escapeToRegexp(@NotNull CharSequence text) { + StringBuilder builder = new StringBuilder(text.length()); + for (int i = 0; i < text.length(); i++) { + final char c = text.charAt(i); + if (c == ' ' || Character.isLetter(c) || Character.isDigit(c) || c == '_' || c == '*') { + builder.append(c); + } + else { + builder.append('\\').append(c); + } + } - //public for tests only + return builder.toString(); + } + + @TestOnly public static String convertToRegexp(String aspectsntx, char separator) { - StringBuffer buf = new StringBuffer(aspectsntx.length()); + StringBuilder buf = new StringBuilder(aspectsntx.length()); int cur = 0; boolean isAfterSeparator = false; boolean isAfterAsterix = false; From 1df6fba2bbd1f5f10d45718464a9ba4fb4d3baf6 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Sep 2014 15:36:01 +0200 Subject: [PATCH 16/78] testdata for IDEA-130129 --- .../lambda/newLambda/IDEA130129.java | 72 +++++++++++++++++++ .../lambda/NewLambdaHighlightingTest.java | 6 +- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA130129.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA130129.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA130129.java new file mode 100644 index 000000000000..8f933f79e7c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA130129.java @@ -0,0 +1,72 @@ +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +class Test +{ + public static class WrapperBase + { + public T unwrap(E edge) + { + //noinspection unchecked + return (T)((DefaultEdge)edge).getSource(); + } + } + + public static class Wrapper extends WrapperBase + { + } + + public static class DefaultEdge + { + private final TaskId taskId; + + public DefaultEdge(TaskId taskId) + { + this.taskId = taskId; + } + + public Object getSource() + { + return taskId; + } + } + + public static class TaskId + { + private final String id; + + public TaskId(String id) + { + this.id = id; + } + + public String getId() + { + return id; + } + + @Override + public String toString() + { + return getId(); + } + } + + public static void main(String[] args) + { + Wrapper w = new Wrapper<>(); + Set s = new HashSet<>(); + s.add(new DefaultEdge(new TaskId("1"))); + s.add(new DefaultEdge(new TaskId("2"))); + s.add(new DefaultEdge(new TaskId("3"))); + + Set processed = s + .stream() + .map(w::unwrap) + .filter(edge -> !edge.getId().equals("")) + .collect(Collectors.toSet()); + + System.out.println(processed); + } +} 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 998ecff12a7c..d6153e6b3d84 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 @@ -22,8 +22,6 @@ import com.intellij.idea.Bombed; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.testFramework.IdeaTestUtil; -import junit.framework.Test; -import junit.framework.TestSuite; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -141,6 +139,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA130129() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } From 68cbd98f061897e7b77703975c54e1cc0fe98fa2 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Sep 2014 15:54:44 +0200 Subject: [PATCH 17/78] external annotations: skip unknown members (IDEA-130273) --- .../codeInsight/ExternalAnnotationsManagerImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index af5f14e25131..c888ca9b9f04 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -544,7 +544,10 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM if (document != null) { final XmlTag rootTag = document.getRootTag(); final String externalName = getExternalName(listOwner, false); - if (rootTag != null) { + if (externalName == null) { + LOG.info("member without external name: " + listOwner); + } + if (rootTag != null && externalName != null) { XmlTag anchor = null; for (XmlTag item : rootTag.getSubTags()) { int compare = Comparing.compare(externalName, StringUtil.unescapeXml(item.getAttributeValue("name"))); @@ -573,10 +576,12 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM text += createAnnotationTag(annotationFQName, values); text += ""; rootTag.addAfter(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText(text), anchor); + commitChanges(xmlFile); + notifyAfterAnnotationChanging(listOwner, annotationFQName, true); + return; } } - commitChanges(xmlFile); - notifyAfterAnnotationChanging(listOwner, annotationFQName, true); + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); } catch (IncorrectOperationException e) { LOG.error(e); From 7ec418c63f5c07d2810e734a09fe89229cc9ce8d Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Mon, 29 Sep 2014 19:01:12 +0400 Subject: [PATCH 18/78] fix rc --- .../groovy/lang/psi/impl/GroovyFileImpl.java | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index bd8cc3ecc4ed..825431b2a238 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -80,12 +80,10 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { } }; - private final Object lock = new Object(); - private volatile Boolean myScript; private volatile GroovyScriptClass myScriptClass; private volatile GrParameter mySyntheticArgsParameter = null; - private PsiElement myContext; + private volatile PsiElement myContext; public GroovyFileImpl(FileViewProvider viewProvider) { super(viewProvider, GroovyLanguage.INSTANCE); @@ -119,16 +117,13 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { } private GrParameter getSyntheticArgsParameter() { - if (mySyntheticArgsParameter == null) { + GrParameter parameter = mySyntheticArgsParameter; + if (parameter == null) { final PsiType psiType = JavaPsiFacade.getElementFactory(getProject()).createTypeFromText("java.lang.String[]", this); - final GrParameter candidate = new GrLightParameter(SYNTHETIC_PARAMETER_NAME, psiType, this); - synchronized (lock) { - if (mySyntheticArgsParameter == null) { - mySyntheticArgsParameter = candidate; - } - } + parameter = new GrLightParameter(SYNTHETIC_PARAMETER_NAME, psiType, this); + mySyntheticArgsParameter = parameter; } - return mySyntheticArgsParameter; + return parameter; } @Override @@ -349,15 +344,12 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { return ((GrFileStub)stub).isScript(); } - if (myScript == null) { - synchronized (lock) { - boolean isScript = checkIsScript(); - if (myScript == null) { - myScript = isScript; - } - } + Boolean isScript = myScript; + if (isScript == null) { + isScript = checkIsScript(); + myScript = isScript; } - return myScript; + return isScript; } private boolean checkIsScript() { @@ -378,34 +370,28 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { @Override public void subtreeChanged() { - synchronized (lock) { - myScript = null; - } + myScript = null; super.subtreeChanged(); } @Override public GroovyScriptClass getScriptClass() { - if (isScript()) { - if (myScriptClass == null) { - GroovyScriptClass candidate = new GroovyScriptClass(this); - synchronized (lock) { - if (myScriptClass == null) { - myScriptClass = candidate; - } - } - } - return myScriptClass; - } - else { + if (!isScript()) { return null; } + + GroovyScriptClass aClass = myScriptClass; + if (aClass == null) { + aClass = new GroovyScriptClass(this); + myScriptClass = aClass; + } + + return aClass; } @Override public void setPackageName(String packageName) { final ASTNode fileNode = getNode(); - assert fileNode != null; final GrPackageDefinition currentPackage = getPackageDefinition(); if (packageName == null || packageName.isEmpty()) { if (currentPackage != null) { @@ -482,10 +468,8 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { @Override public void clearCaches() { super.clearCaches(); - synchronized (lock) { - myScriptClass = null; - mySyntheticArgsParameter = null; - } + myScriptClass = null; + mySyntheticArgsParameter = null; } @Override From b320c436530eaf563604d930a09163f7e6ed93d8 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 29 Sep 2014 19:01:01 +0400 Subject: [PATCH 19/78] Fix for cursor moving for a text component only. --- .../src/com/intellij/ui/popup/AbstractPopup.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 3c01fdd78d53..7274d0930824 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -56,6 +56,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.event.*; import java.util.HashSet; @@ -901,7 +902,9 @@ public class AbstractPopup implements JBPopup { public void run() { if (myPreferredFocusedComponent != null && myInStack && myFocusable) { myFocusTrackback.registerFocusComponent(myPreferredFocusedComponent); - IJSwingUtilities.moveMousePointerOn(myPreferredFocusedComponent); + if (myPreferredFocusedComponent instanceof JTextComponent) { + IJSwingUtilities.moveMousePointerOn(myPreferredFocusedComponent); + } } removeActivity(); From e0e1f3269042bd67c5d8bbc14467d1f2ea56b30e Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Mon, 29 Sep 2014 16:43:37 +0200 Subject: [PATCH 20/78] sync GPUB --- .../lang/parser/GeneratedParserUtilBase.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java index 267333399dbd..8ad37418f660 100644 --- a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java +++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java @@ -1,3 +1,19 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // This class is a runtime engine for parsers generated by Grammar-Kit. // Do not modify or refactor without complete investigation and/or review. package com.intellij.lang.parser; @@ -107,6 +123,11 @@ public class GeneratedParserUtilBase { return TokenSet.create(tokenTypes_); } + public static boolean leftMarkerIs(PsiBuilder builder_, IElementType type) { + LighterASTNode marker = builder_.getLatestDoneMarker(); + return marker != null && marker.getTokenType() == type; + } + private static boolean consumeTokens(PsiBuilder builder_, boolean smart, int pin, IElementType... tokens) { ErrorState state = ErrorState.get(builder_); if (state.completionState != null && state.predicateCount == 0) { From ca690981cff6d179490e6478d99c00aa2ec64c49 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Mon, 29 Sep 2014 19:38:41 +0400 Subject: [PATCH 21/78] DBE: fix broken highlighting in EditorTextFieldRenderer --- .../com/intellij/ui/EditorTextFieldCellRenderer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index a9510359c76b..06b4a9ddcd70 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -140,7 +140,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, } public void setText(String text) { - setText(text, true); + setText(text, false); } @Override @@ -187,7 +187,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, } } - setText(myDocumentTextBuilder.toString(), false); + setText(myDocumentTextBuilder.toString(), true); } private static void appendAbbreviatedLine(StringBuilder to, String line, FontMetrics metrics, int maxWidth) { @@ -212,8 +212,10 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, } } - private void setText(String text, boolean updatePreferredSize) { - myEditor.getMarkupModel().removeAllHighlighters(); + private void setText(String text, boolean abbreviationOfCurrentText) { + if (!abbreviationOfCurrentText) { + myEditor.getMarkupModel().removeAllHighlighters(); + } myEditor.getDocument().setText(text); myEditor.getHighlighter().setText(text); @@ -222,7 +224,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, SelectionModel selectionModel = myEditor.getSelectionModel(); selectionModel.setSelection(0, selectionModel.hasSelection() ? myEditor.getDocument().getTextLength() : 0); - if (updatePreferredSize) { + if (!abbreviationOfCurrentText) { myPreferredSize = super.getPreferredSize(); } } From 2b7a5073592e90da9f623a8b6cea98a9a96997af Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Mon, 29 Sep 2014 19:18:32 +0400 Subject: [PATCH 22/78] return ChildRole.COMMA for comma between fields in anonymous class (IDEA-130275) --- .../source/tree/java/AnonymousClassElementBase.java | 3 +++ .../psi/formatter/java/JavaFormatterSpaceTest.java | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnonymousClassElementBase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnonymousClassElementBase.java index c52bf6f41214..161c80c92466 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnonymousClassElementBase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnonymousClassElementBase.java @@ -85,6 +85,9 @@ public abstract class AnonymousClassElementBase extends ClassElement { else if (i == JavaTokenType.RBRACE) { return getChildRole(child, ChildRole.RBRACE); } + else if (i == JavaTokenType.COMMA) { + return ChildRole.COMMA; + } else { return ChildRoleBase.NONE; } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java index c01395b66869..0debdda7b434 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterSpaceTest.java @@ -579,4 +579,14 @@ public class JavaFormatterSpaceTest extends AbstractJavaFormatterTest { doMethodTest(before, "Test.class"); } + public void testMultipleFieldDeclaration_InAnonymousClass() { + doMethodTest( + "new Object() {\n" + + "boolean one, two;\n" + + "};", + "new Object() {\n" + + " boolean one, two;\n" + + "};" + ); + } } From ac7bb649887e60e616ef308b56c482a70c067c12 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 29 Sep 2014 16:54:36 +0200 Subject: [PATCH 23/78] dumb aware inspection settings --- .../codeInspection/ui/AdvancedSettingsAction.java | 5 +++-- .../codeInspection/ui/LevelChooserAction.java | 9 +++++---- .../profile/codeInspection/ui/ScopesChooser.java | 13 +++++++------ .../ui/SingleInspectionProfilePanel.java | 7 ++++--- .../ui/filter/InspectionFilterAction.java | 14 ++++++++------ 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AdvancedSettingsAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AdvancedSettingsAction.java index 80872cecd9f1..fb4e2e67732c 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AdvancedSettingsAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AdvancedSettingsAction.java @@ -17,8 +17,9 @@ package com.intellij.profile.codeInspection.ui; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; @@ -38,7 +39,7 @@ import java.awt.*; /** * @author Dmitry Batkovich */ -public abstract class AdvancedSettingsAction extends AnAction { +public abstract class AdvancedSettingsAction extends DumbAwareAction { private final int myCheckBoxIndent; private Project myProject; private InspectionConfigTreeNode myRoot; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java index df3b8bda3f3b..f8fdecd3020b 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java @@ -22,11 +22,12 @@ import com.intellij.codeInsight.daemon.impl.SeverityUtil; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.codeInspection.ex.SeverityEditorDialog; import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.profile.codeInspection.SeverityProvider; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ import java.util.TreeSet; /** * @author Dmitry Batkovich */ -public abstract class LevelChooserAction extends ComboBoxAction { +public abstract class LevelChooserAction extends ComboBoxAction implements DumbAware { private final SeverityRegistrar mySeverityRegistrar; private HighlightSeverity myChosen = null; @@ -62,7 +63,7 @@ public abstract class LevelChooserAction extends ComboBoxAction { group.add(action); } group.addSeparator(); - group.add(new AnAction("Edit severities...") { + group.add(new DumbAwareAction("Edit severities...") { @Override public void actionPerformed(final AnActionEvent e) { final SeverityEditorDialog dlg = new SeverityEditorDialog(anchor, myChosen, mySeverityRegistrar); @@ -101,7 +102,7 @@ public abstract class LevelChooserAction extends ComboBoxAction { templatePresentation.setIcon(HighlightDisplayLevel.find(severity).getIcon()); } - private class HighlightSeverityAction extends AnAction { + private class HighlightSeverityAction extends DumbAwareAction { private final HighlightSeverity mySeverity; public HighlightSeverity getSeverity() { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java index fde3b141084d..d5a6ac7b0e3f 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java @@ -17,10 +17,11 @@ package com.intellij.profile.codeInspection.ui; import com.intellij.codeInspection.ex.Descriptor; import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.psi.search.scope.NonProjectFilesScope; import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; @@ -31,14 +32,14 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.ArrayList; -import java.util.Set; -import java.util.List; import java.util.Collections; +import java.util.List; +import java.util.Set; /** * @author Dmitry Batkovich */ -public abstract class ScopesChooser extends ComboBoxAction { +public abstract class ScopesChooser extends ComboBoxAction implements DumbAware { public static final String TITLE = "Select a scope to change its settings"; private final List myDefaultDescriptors; @@ -82,7 +83,7 @@ public abstract class ScopesChooser extends ComboBoxAction { fillActionGroup(group, customScopes, myDefaultDescriptors, myInspectionProfile, myExcludedScopeNames); group.addSeparator(); - group.add(new AnAction("Edit Scopes Order...") { + group.add(new DumbAwareAction("Edit Scopes Order...") { @Override public void actionPerformed(final AnActionEvent e) { final ScopesOrderDialog dlg = new ScopesOrderDialog(component, myInspectionProfile, myProject); @@ -110,7 +111,7 @@ public abstract class ScopesChooser extends ComboBoxAction { if (excludedScopeNames.contains(scopeName)) { continue; } - group.add(new AnAction(scopeName) { + group.add(new DumbAwareAction(scopeName) { @Override public void actionPerformed(final AnActionEvent e) { for (final Descriptor defaultDescriptor : defaultDescriptors) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index e086d9aa9610..fbcbe1a6d0d1 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -38,6 +38,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.Splitter; @@ -64,7 +65,8 @@ import com.intellij.ui.components.JBLabel; import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.config.StorageAccessors; -import com.intellij.util.containers.*; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xml.util.XmlStringUtil; @@ -86,7 +88,6 @@ import java.awt.*; import java.io.IOException; import java.io.StringReader; import java.util.*; -import java.util.HashSet; import java.util.List; /** @@ -365,7 +366,7 @@ public class SingleInspectionProfilePanel extends JPanel { actions.add(actionManager.createExpandAllAction(myTreeExpander, myTreeTable)); actions.add(actionManager.createCollapseAllAction(myTreeExpander, myTreeTable)); - actions.add(new AnAction("Reset to Empty", "Reset to empty", AllIcons.Actions.Reset_to_empty){ + actions.add(new DumbAwareAction("Reset to Empty", "Reset to empty", AllIcons.Actions.Reset_to_empty){ @Override public void update(AnActionEvent e) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java index 75146cbb36a5..155d95ce7213 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java @@ -22,6 +22,8 @@ import com.intellij.icons.AllIcons; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.CheckboxAction; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.profile.codeInspection.SeverityProvider; import com.intellij.profile.codeInspection.ui.LevelChooserAction; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; @@ -32,7 +34,7 @@ import java.util.SortedSet; /** * @author Dmitry Batkovich */ -public class InspectionFilterAction extends DefaultActionGroup implements Toggleable { +public class InspectionFilterAction extends DefaultActionGroup implements Toggleable, DumbAware { private final SeverityRegistrar mySeverityRegistrar; private final InspectionsFilter myInspectionsFilter; @@ -69,7 +71,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle add(new ShowOnlyCleanupInspectionsAction()); } - private class ResetFilterAction extends AnAction { + private class ResetFilterAction extends DumbAwareAction { public ResetFilterAction() { super("Reset Filter"); } @@ -86,7 +88,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle } } - private class ShowOnlyCleanupInspectionsAction extends CheckboxAction { + private class ShowOnlyCleanupInspectionsAction extends CheckboxAction implements DumbAware{ public ShowOnlyCleanupInspectionsAction() { super("Show Only Cleanup Inspections"); } @@ -102,7 +104,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle } } - private class ShowAvailableOnlyOnAnalyzeInspectionsAction extends CheckboxAction { + private class ShowAvailableOnlyOnAnalyzeInspectionsAction extends CheckboxAction implements DumbAware { public ShowAvailableOnlyOnAnalyzeInspectionsAction() { super("Show Only \"Available only for Analyze | Inspect Code\""); @@ -119,7 +121,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle } } - private class ShowWithSpecifiedSeverityInspectionsAction extends CheckboxAction { + private class ShowWithSpecifiedSeverityInspectionsAction extends CheckboxAction implements DumbAware { private final HighlightSeverity mySeverity; @@ -146,7 +148,7 @@ public class InspectionFilterAction extends DefaultActionGroup implements Toggle } } - private class ShowEnabledOrDisabledInspectionsAction extends CheckboxAction { + private class ShowEnabledOrDisabledInspectionsAction extends CheckboxAction implements DumbAware{ private final Boolean myShowEnabledActions; From 3f7afaad9ea61d51cbeb047cddd66e1b0d86704d Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 29 Sep 2014 17:28:22 +0200 Subject: [PATCH 24/78] Remove SearchStarter [CR-IC-6343] --- .../plugin/replace/ui/ReplaceCommand.java | 9 ++++++--- .../plugin/replace/ui/ReplaceUsageViewContext.java | 3 +-- .../structuralsearch/plugin/ui/SearchCommand.java | 5 ++--- .../structuralsearch/plugin/ui/SearchStarter.java | 9 --------- .../structuralsearch/plugin/ui/UsageViewContext.java | 7 +++---- 5 files changed, 12 insertions(+), 21 deletions(-) delete mode 100644 platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchStarter.java diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java index ed5ebaaf4e2c..af0d230edbfb 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java @@ -2,7 +2,10 @@ package com.intellij.structuralsearch.plugin.replace.ui; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.plugin.StructuralSearchPlugin; -import com.intellij.structuralsearch.plugin.ui.*; +import com.intellij.structuralsearch.plugin.ui.Configuration; +import com.intellij.structuralsearch.plugin.ui.SearchCommand; +import com.intellij.structuralsearch.plugin.ui.SearchContext; +import com.intellij.structuralsearch.plugin.ui.UsageViewContext; import com.intellij.usages.Usage; /** @@ -21,9 +24,9 @@ public class ReplaceCommand extends SearchCommand { } protected UsageViewContext createUsageViewContext() { - final SearchStarter searchStarter = new SearchStarter() { + final Runnable searchStarter = new Runnable() { @Override - public void startSearch() { + public void run() { new ReplaceCommand(myConfiguration, mySearchContext).startSearching(); } }; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java index 17618cb0fc53..7ef3a906906a 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java @@ -10,7 +10,6 @@ import com.intellij.structuralsearch.plugin.replace.ReplacementInfo; import com.intellij.structuralsearch.plugin.replace.impl.Replacer; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchContext; -import com.intellij.structuralsearch.plugin.ui.SearchStarter; import com.intellij.structuralsearch.plugin.ui.UsageViewContext; import com.intellij.usageView.UsageInfo; import com.intellij.usages.Usage; @@ -32,7 +31,7 @@ class ReplaceUsageViewContext extends UsageViewContext { private final HashMap usage2ReplacementInfo = new HashMap(); private final Replacer replacer = new Replacer(mySearchContext.getProject(), ((ReplaceConfiguration)myConfiguration).getOptions()); - ReplaceUsageViewContext(SearchContext context, Configuration configuration, SearchStarter searchStarter) { + ReplaceUsageViewContext(SearchContext context, Configuration configuration, Runnable searchStarter) { super(configuration, context, searchStarter); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java index 83ae8d836386..d4c4c8247074 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java @@ -11,7 +11,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.psi.PsiDocumentManager; @@ -46,9 +45,9 @@ public class SearchCommand { } protected UsageViewContext createUsageViewContext() { - final SearchStarter searchStarter = new SearchStarter() { + final Runnable searchStarter = new Runnable() { @Override - public void startSearch() { + public void run() { new SearchCommand(myConfiguration, mySearchContext).startSearching(); } }; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchStarter.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchStarter.java deleted file mode 100644 index 457df61be46d..000000000000 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchStarter.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.intellij.structuralsearch.plugin.ui; - -/** - * @author Bas Leijdekkers - */ -public interface SearchStarter { - - void startSearch(); -} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/UsageViewContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/UsageViewContext.java index db93e804b186..1f592e6cf534 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/UsageViewContext.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/UsageViewContext.java @@ -11,7 +11,6 @@ import com.intellij.psi.PsiFile; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.SSRBundle; import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration; -import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration; import com.intellij.usages.ConfigurableUsageTarget; import com.intellij.usages.Usage; import com.intellij.usages.UsageView; @@ -30,12 +29,12 @@ import java.util.Set; */ public class UsageViewContext { protected final SearchContext mySearchContext; - private final SearchStarter mySearchStarter; + private final Runnable mySearchStarter; private UsageView myUsageView; protected final Configuration myConfiguration; private Set myExcludedSet; - protected UsageViewContext(Configuration configuration, SearchContext searchContext, SearchStarter searchStarter) { + protected UsageViewContext(Configuration configuration, SearchContext searchContext, Runnable searchStarter) { myConfiguration = configuration; mySearchContext = searchContext; mySearchStarter = searchStarter; @@ -102,7 +101,7 @@ public class UsageViewContext { @Override public void findUsages() { - mySearchStarter.startSearch(); + mySearchStarter.run(); } @Override From 4b0a966ce8332bf40d150ac061fa168276b1586c Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 29 Sep 2014 19:49:32 +0400 Subject: [PATCH 25/78] IDEA-130338 Please restore previous mapIds for topics in Settings/Preferences dialog Support two new topics. --- .../intellij/json/formatter/JsonCodeStyleSettingsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/src/com/intellij/json/formatter/JsonCodeStyleSettingsProvider.java b/json/src/com/intellij/json/formatter/JsonCodeStyleSettingsProvider.java index 712a4cdedb88..4ecf87470467 100644 --- a/json/src/com/intellij/json/formatter/JsonCodeStyleSettingsProvider.java +++ b/json/src/com/intellij/json/formatter/JsonCodeStyleSettingsProvider.java @@ -37,7 +37,7 @@ public class JsonCodeStyleSettingsProvider extends CodeStyleSettingsProvider { @Nullable @Override public String getHelpTopic() { - return null; + return "reference.settingsdialog.codestyle.json"; } }; } From 3f0f22ec650f93655d2c28cae7b1649661ef78f2 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 29 Sep 2014 19:54:05 +0400 Subject: [PATCH 26/78] fixed tests for the first task in first lesson --- .../resources/courses/introduction_course.zip | Bin 95274 -> 95285 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/python/edu/learn-python/resources/courses/introduction_course.zip b/python/edu/learn-python/resources/courses/introduction_course.zip index 4fd2dab43830258f6ffcf477efe0379c687493da..bf38085c8f6fa27ceced439f81ee9435a252d160 100644 GIT binary patch delta 3623 zcmZuzc|4W*8b9w5PLfnI9P4QvOFATmk|h!mSxPCQ6gNvm8g)BNF}4SS=RKOw{e$OupXd90pXIlmpW0Nb+f;YWRI!(s zk)~jSf+e$693*BZix;S>d?PWF%2aIytU)?ntA99v3fy&wSkHNgZcBdE8}Y@rw*D92 zS~I2v2My<`9KP5Q$mT%`TXOzyu<8E~rbZlv4qvd>2$k%wg-%0!4A#Jht((Ygbx4Up z6zHmkG{`c;G|neBiXOD-l9NV=V`HWoM{<}-;|-vjm}GIb^CnwBcQV}%^0jHspwuDh zqK%;cSCk7fd;C8^I+^Mb(+NqS|1jY@kiv-)kUviR7Np)JjH#HE58t+v_km<enZ?eOgv$=KbmA&N*>Tm5UfUoeID0fuCb4_*tGtM~->U5YRDm~#dk<2;*Mnbx(^~v#wUN%%(8JPu6>9kd+6h#>m z{_1&{Y4zY(L)Og0l;zQKE@gF$C!jvZjKNGgYxPkP$A)lZbgr1vB4^@USSw(Z^%bfZK}Ew)w&VM zY`(?CA>L^?U7t;!9E#4fXQ~TqHzeXsYIMClHA;iIkPCKp1hQE_ZZ-yDl8~e)wcDbJ zA0CoViW$(J4ovu!7(-g(KzYn{Wfo?eA~9c0q@L2a%pK6 zvuyb27?Tg*<6-d3z6fxQ9Ar=Yy=72)d!J*1weKlW!TL*OxUR1c0lapP8-4 zW==o0R@s8)38V@?Q3p=5lVOO;J;mHQin6Xsu`I2BzeI0WHFIRxH@xR`9hdR>885I+ zIeQLdLD^X8z}bliH2L*02mI=s2LQs)J!7SG)_LX-uu9g2!5fpkS8vt018QvTJ#e#?2mJule#qR=gXe+7JqiGp z%a3k>v*0mq1!?UQKSYgw76XXzmSFPxvn7DCdd|E8?7)3qj7AiDcGDVz0C}%59i+HN zPa6AjF7{IWs-H`G`}IPI7Bw+@gr#wPGX<5ke*`J{UNqx8ru@m=1?)V+TWT?`l{o~8 zz2(&gC{ol0?U5br^#ES_cB6{8)QPy>uqc#`RL_%`1ywK{Y@t>%Uw~|pc@f`t7{2FS z?pPfjk0;TOe<>SB@Tg&JDm)(is}68ldqu3> z_|ZaZ+DXx#(}BbL{2ik#lFcg&FVC*??2AaY5q+*X_2Yw_=haJNJ70ePa!yIA8sF<; zX|Id%6U{s7-R0M=>;GZ7AoQu*;gG;{nXWlLuT)euy=%H}oKEqqKXtSs{!!YNO_HZw zc}cYEtX8K7wO@Pe<(2fT(LQnE;+oFnqDNJSB6euVYuD9GEgn<)`csp2;=as9pH7@r zkzIBR>n)7Z2y8xHT-2aDSF~abyL*?T@>d`8NVAvz!hZY_ z^|=3N3cLKYNK6^f2jVCT6=vz^g?f}ONgq(7WpUI7+EhplqaVgoLjDCAEsv+>vo6yw z)}PPgne+6ReZk`~+ktl|V^0U25l>kw*bHg61j?8)qazZiXex^plj-gRDuBPCiv=1H zfBA6obC(94ypD3=S9U9m0`j6;lWt{=E+zR>3vC*7r&~Hvk1t`J}p{*Jwv0~ue8$X>nR_8{@*OB^uT(`Qq5w3?eBl!GBDl% delta 3679 zcmZvec|2BGAHbb^BSpp&iU*;nA*5_$t4#Ji^rnO)BD)q^WXV|C^f>Caj5JxMY1b`N z(?WaAt4Z}vyQWkkT1-Wysk!%e9@q1HKCeIge)pX3Z#~O%j4x!4k0m4=~cEi4#Fe7w`0{wGiSBT6oZu~R| zpVl5Mi(+*h6`5~W8Ql(_l$)~~X8r%%Dq}~n1BG*h==ii))}=CT6Wdch8~f)uUe}M$ zA9vem;tJhZ&=vI!t&>_?V>#fKQ2zt8(@$GL(dUMNi1)VPC;wKE`@L&Sz$xJI!17FWm zt2lav;q+ooe_>w({>r{P2Qtu63nx27N_Ab_;SeL$GePn-v^WmQ+2*GF~m!RUANv?>u>JFgJYnw&CW z{$U|FPcvc*t|;|5M{w>R$E^gvvSACnU`cRQe78&rs>~fr4nLRR0Myrn;RM%A)FFyh zQka~3{7Z5GB=afxC78TOL4FB;C!mLw~|ziwkeTR&9*l{fUfN!0tl(jtsqyx-U=1c^W!`I1X5CIFOa;; zXFI3ExWi8z$T!k+*Br7TYO9Q7N#=qN8jgFaZGp0^nL+Tv+7gn=@ZA-1i`u*!4jvx! z%VV$@yk|Vg#CGpjS&;D!;5JU|JU!f8uf&uDAg!U?^FmVE6~ec;dfyqaj^EGiKmM-E zJ&-75Rd#3&KZ&CbT>{9oE|NfN4(lW2!PHGhntYAtS<*JOBM(W^uaA<`gx}U*lFbF* z{}t{(Jnq;D@GPm+U_Tr)CW#yTc3Tb}dBUB9KXDJjJD>C<;R{a<+{d`_H0gsz!*!sZ zH_Rptb30Qh=Wftha=nM1y$Ejg&ymKV^X@{$u(k^>gaB~rLOFO0y%<0ethscj-y>i4 zw#$K1P6sPqA@7N*D=lEN`uB1~Ws`>$&)PJ3(b+j7HmAuB@d`e6^*Ri!`(p~C@})1Z zN7usXd~R}b^A?bIo8R)1y>{IJQH4^7|8X$A=}i}MU{sqJm)EIdC98(>5Qln z894b?FkQmIXKyv}l9k-%b_%aF+zCXeiV?+1Z|Dj4d~w}p4V>EMj&IzX#p~?k`_g^u z_dq1HiLYpRODI%-y(O1)=^?i{_}y~!uipMHK|8NLA}7G;vGh03wRIfXCW%i%5mnv) zKvu>No_f*MTSe@+XVRM@s*M~!qvtAevAx^LMN!_~3n4djTmd=zMHc0rfu~+JFY6qp z6#ejJ{}Y-|*s_zX|Ef;!VH;wuc$60b#=u>?X$){V_uZbbtwPbXAQ>-HUTnn^v$Ti0Ck=3qj( z*jQ9iU!dIQk|f$6S9Gl6!@(#Ula#L>^&j8pdp&UqaqSAvf0&6pF5ca*YprxO6`$%1 zraigUAKtYFTfFk<-vNB%H@*sjsVA@6;EHK_&AoYe_MbPIyks-G!{wIu_21qw?({YW zK=!A15kx^fVZ?M!?`l9=d-pA&-7~&nB+1Bw=2o1UJ_hMAJ;`XPNN$lS1qCxEI|bP= z#SuuA=9Zd?o`?*Yv=k(!roCj&q#=Er)}hE8NI|Cf(I+LwKNXFlM!n)^OqjA%^gXpg z`q7t)f~myUWTwaksWJI!$OUa@8q-h)HL{yb%t}W-RQBIYcLrzwdpc)-Px_ISz?rya wAQ#H@9Zci(?}jo5Gtg92!Mw>pi>XgN#BA*% Date: Mon, 29 Sep 2014 16:15:38 +0200 Subject: [PATCH 27/78] print misbehaving console filters (EA-60861) --- .../execution/filters/CompositeFilter.java | 4 ++++ .../execution/impl/EditorHyperlinkSupport.java | 18 ++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java index fb782db28cd4..5bdf700b4387 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/CompositeFilter.java @@ -187,4 +187,8 @@ public class CompositeFilter implements Filter, FilterMixin { this.forceUseAllFilters = forceUseAllFilters; } + @Override + public String toString() { + return "CompositeFilter: " + myFilters; + } } diff --git a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java index d263288634b7..67d655fd0bad 100644 --- a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java +++ b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java @@ -19,6 +19,7 @@ import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.HyperlinkInfo; import com.intellij.execution.filters.HyperlinkInfoBase; import com.intellij.ide.OccurenceNavigator; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; @@ -59,6 +60,7 @@ import java.util.Map; * @author peter */ public class EditorHyperlinkSupport { + private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.EditorHyperlinkSupport"); public static final Key OLD_HYPERLINK_TEXT_ATTRIBUTES = Key.create("OLD_HYPERLINK_TEXT_ATTRIBUTES"); private static final Key HYPERLINK = Key.create("HYPERLINK"); private static final int HYPERLINK_LAYER = HighlighterLayer.SELECTION - 123; @@ -266,11 +268,19 @@ public class EditorHyperlinkSupport { Filter.Result result = customFilter.applyFilter(text, endOffset); if (result != null) { for (Filter.ResultItem resultItem : result.getResultItems()) { - if (resultItem.getHyperlinkInfo() != null) { - createHyperlink(resultItem.getHighlightStartOffset(), resultItem.getHighlightEndOffset(), resultItem.getHighlightAttributes(), resultItem.getHyperlinkInfo()); + int start = resultItem.getHighlightStartOffset(); + int end = resultItem.getHighlightEndOffset(); + if (end < start || end > document.getTextLength()) { + LOG.error("Filter returned wrong range: start=" + start + "; end=" + end + "; length=" + document.getTextLength() + "; filter=" + customFilter); + continue; } - else if (resultItem.getHighlightAttributes() != null) { - addHighlighter(resultItem.getHighlightStartOffset(), resultItem.getHighlightEndOffset(), resultItem.getHighlightAttributes()); + + TextAttributes attributes = resultItem.getHighlightAttributes(); + if (resultItem.getHyperlinkInfo() != null) { + createHyperlink(start, end, attributes, resultItem.getHyperlinkInfo()); + } + else if (attributes != null) { + addHighlighter(start, end, attributes); } } } From a3731a26e714990b2c967575651bdb71ef781879 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 16:20:59 +0200 Subject: [PATCH 28/78] make SmartList.sort compatible with java 8 --- platform/util/src/com/intellij/util/SmartList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/SmartList.java b/platform/util/src/com/intellij/util/SmartList.java index 207c132473d2..775b63e8e887 100644 --- a/platform/util/src/com/intellij/util/SmartList.java +++ b/platform/util/src/com/intellij/util/SmartList.java @@ -236,7 +236,7 @@ public class SmartList extends AbstractList { } } - public void sort(@NotNull Comparator comparator) { + public void sort(Comparator comparator) { if (mySize >= 2) { Arrays.sort((E[])myElem, 0, mySize, comparator); } From 90217aaf20d3ec6d0a62f9dcb5655ff4dac5decc Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 16:25:44 +0200 Subject: [PATCH 29/78] make local history fileCreated event processing tolerant to recursive symlinks --- .../LocalHistoryEventDispatcher.java | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/LocalHistoryEventDispatcher.java b/platform/lvcs-impl/src/com/intellij/history/integration/LocalHistoryEventDispatcher.java index a9a87bac411b..98f6b1f1348c 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/LocalHistoryEventDispatcher.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/LocalHistoryEventDispatcher.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class LocalHistoryEventDispatcher extends VirtualFileAdapter implements VirtualFileManagerListener, CommandListener { private static final Key WAS_VERSIONED_KEY = @@ -89,19 +90,25 @@ public class LocalHistoryEventDispatcher extends VirtualFileAdapter implements V } private void createRecursively(VirtualFile f) { - if (isVersioned(f)) { - myVcs.created(f.getPath(), f.isDirectory()); - } - if (f.isDirectory()) { - // For unversioned files we try to get cached children in hope that they are already generated by content root manager: - // cached children may mean that there are versioned sub-folders or sub-files. - Iterable children = myGateway.isVersioned(f, true) - ? IdeaGateway.loadAndIterateChildren(f) - : IdeaGateway.iterateDBChildren(f); - for (VirtualFile each : children) { - createRecursively(each); + VfsUtilCore.visitChildrenRecursively(f, new VirtualFileVisitor() { + @Override + public boolean visitFile(@NotNull VirtualFile f) { + if (isVersioned(f)) { + myVcs.created(f.getPath(), f.isDirectory()); + } + return true; } - } + + @Nullable + @Override + public Iterable getChildrenIterable(@NotNull VirtualFile f) { + // For unversioned files we try to get cached children in hope that they are already generated by content root manager: + // cached children may mean that there are versioned sub-folders or sub-files. + return myGateway.isVersioned(f, true) + ? IdeaGateway.loadAndIterateChildren(f) + : IdeaGateway.iterateDBChildren(f); + } + }); } @Override From de1d8851c88175ebe09ab9772a18c9f948c68578 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 16:48:16 +0200 Subject: [PATCH 30/78] use PsiUtilCore.ensureValid (EA-60716) --- platform/lang-api/src/com/intellij/psi/PsiElementRef.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/psi/PsiElementRef.java b/platform/lang-api/src/com/intellij/psi/PsiElementRef.java index dd1044582297..5988ec808437 100644 --- a/platform/lang-api/src/com/intellij/psi/PsiElementRef.java +++ b/platform/lang-api/src/com/intellij/psi/PsiElementRef.java @@ -16,6 +16,7 @@ package com.intellij.psi; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -94,7 +95,7 @@ public final class PsiElementRef { private final T myElement; public Real(@NotNull T element) { - LOG.assertTrue(element.isValid()); + PsiUtilCore.ensureValid(element); myElement = element; } From bdf4a15c68ee8d18cb1a978537812d3428bafcee Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 16:52:51 +0200 Subject: [PATCH 31/78] goto class: null name for invalid elements (EA-60372) --- .../intellij/ide/util/gotoByName/GotoClassModel2.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java index 8d80a1c1fbac..72b740fb98c1 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoClassModel2.java @@ -22,7 +22,6 @@ import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.navigation.GotoClassContributor; import com.intellij.navigation.NavigationItem; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.psi.PsiElement; @@ -102,9 +101,13 @@ public class GotoClassModel2 extends FilteringGotoByModel { @Override public String getFullName(final Object element) { - for(ChooseByNameContributor c: getContributors()) { + if (element instanceof PsiElement && !((PsiElement)element).isValid()) { + return null; + } + + for (ChooseByNameContributor c : getContributors()) { if (c instanceof GotoClassContributor) { - String result = ((GotoClassContributor) c).getQualifiedName((NavigationItem) element); + String result = ((GotoClassContributor)c).getQualifiedName((NavigationItem)element); if (result != null) return result; } } From feda68ba24b28da7cbe8f961459949b183fe25e0 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 17:00:34 +0200 Subject: [PATCH 32/78] don't calc choose by name items for closed projects (EA-59690) --- .../src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index f562f2b575ec..13dc53302b79 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -1514,6 +1514,8 @@ public abstract class ChooseByNameBase { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { + if (myProject.isDisposed()) return; + ApplicationAdapter listener = new ApplicationAdapter() { @Override public void beforeWriteActionStart(Object action) { From b202eddc55c9ca72e7c1fd9c71860631046823ab Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 17:21:05 +0200 Subject: [PATCH 33/78] ensure vfs children id array doesn't contain negative numbers (EA-59186) --- .../intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index bc898a49987b..7c35ffc56ff8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -316,6 +316,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { for (int i = 0; i < childrenIds.length; i++) { FSRecords.NameId child = childrenIds[i]; result[i] = child.id; + assert child.id > 0 : child; prevChildren.remove(child.id); if (VfsData.getFileById(child.id, this) == null) { createChild(child.nameId, child.id, delegate); @@ -426,6 +427,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { int i = -negativeIndex -1; System.arraycopy(array, 0, appended, 0, i); appended[i] = file.getId(); + assert appended[i] > 0 : file; System.arraycopy(array, i, appended, i + 1, array.length - i); myData.myChildrenIds = appended; } From eccc21743aac96146c9ac9d9f015106748d12bfd Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 17:45:10 +0200 Subject: [PATCH 34/78] more diagnostics for EA-58991 - assert: ChooseByNameBase$CalcElementsThread$$.run --- .../com/intellij/ide/util/gotoByName/ChooseByNameBase.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 13dc53302b79..66b590aa9b96 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -1024,6 +1024,7 @@ public abstract class ChooseByNameBase { } private void scheduleCalcElements(final CalcElementsThread thread) { + ApplicationManager.getApplication().assertIsDispatchThread(); myCalcElementsThread = thread; ApplicationManager.getApplication().executeOnPooledThread(thread); } @@ -1561,7 +1562,8 @@ public abstract class ChooseByNameBase { @Override public void run() { if (!myCancelled.isCanceled()) { - LOG.assertTrue(myCalcElementsThread == CalcElementsThread.this); + CalcElementsThread currentBgProcess = myCalcElementsThread; + LOG.assertTrue(currentBgProcess == CalcElementsThread.this, currentBgProcess); myCallback.consume(edt ? filter(elements) : filtered); } } @@ -1620,6 +1622,7 @@ public abstract class ChooseByNameBase { } private boolean cancel() { + ApplicationManager.getApplication().assertIsDispatchThread(); if (myCancelled.isCanceled()) { return false; } From f5d4d942108f27aaeb14a288b7a7f8a99ae1b551 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 29 Sep 2014 17:49:29 +0200 Subject: [PATCH 35/78] tolerate unnamed fields in completion (EA-58807) --- .../completion/JavaMemberNameCompletionContributor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java index bb45d770dea1..ab86b701c3fc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java @@ -382,6 +382,7 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { for (final PsiField field : psiClass.getFields()) { if (field == element) continue; + if (StringUtil.isEmpty(field.getName())) continue; PsiUtilCore.ensureValid(field); PsiType fieldType = field.getType(); From c4c5ca5539d8c719502f24289d945f54045ddc4c Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 29 Sep 2014 18:27:58 +0200 Subject: [PATCH 36/78] Don't show unrelated tips in Edu Edition. --- .../python/edu/PyCharmEduInitialConfigurator.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java index 2954f7c5b706..7bee168b7573 100644 --- a/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java +++ b/python/edu/src/com/jetbrains/python/edu/PyCharmEduInitialConfigurator.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.edu; +import com.google.common.collect.Sets; import com.intellij.application.options.InitialConfigurationDialog; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.intention.IntentionActionBean; @@ -25,6 +26,7 @@ import com.intellij.ide.RecentProjectsManagerBase; import com.intellij.ide.SelectInTarget; import com.intellij.ide.ui.UISettings; import com.intellij.ide.util.PropertiesComponent; +import com.intellij.ide.util.TipAndTrickBean; import com.intellij.notification.EventLog; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; @@ -67,6 +69,8 @@ public class PyCharmEduInitialConfigurator { @NonNls private static final String CONFIGURED = "PyCharmEDU.InitialConfiguration"; + private static final Set UNRELATED_TIPS = Sets.newHashSet("LiveTemplatesDjango.html", "TerminalOpen.html", + "Terminal.html", "ConfiguringTerminal.html"); public static class First { @@ -193,6 +197,13 @@ public class PyCharmEduInitialConfigurator { } } + // unregister unrelated tips + for (TipAndTrickBean tip : Extensions.getExtensions(TipAndTrickBean.EP_NAME)) { + if (UNRELATED_TIPS.contains(tip.fileName)) { + rootArea.getExtensionPoint(TipAndTrickBean.EP_NAME).unregisterExtension(tip); + } + } + for (IntentionActionBean ep : Extensions.getExtensions(IntentionManager.EP_INTENTION_ACTIONS)) { if ("org.intellij.lang.regexp.intention.CheckRegExpIntentionAction".equals(ep.className)) { rootArea.getExtensionPoint(IntentionManager.EP_INTENTION_ACTIONS).unregisterExtension(ep); From ad59b35a196b85ef4b8a6172f6110810d0db9ac3 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 29 Sep 2014 20:49:56 +0400 Subject: [PATCH 37/78] Set minimum size for the Settings tree --- .../com/intellij/openapi/options/newEditor/SettingsTreeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java index 67fe6cb4ed86..381bb7159796 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java @@ -136,6 +136,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd myBuilder = new MyBuilder(new SimpleTreeStructure.Impl(myRoot)); myBuilder.setFilteringMerge(300, null); + setMinimumSize(new Dimension(200, 100)); Disposer.register(this, myBuilder); } From 63fb7d95099e734d04266890a01b05352824e59e Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 29 Sep 2014 23:28:41 +0400 Subject: [PATCH 38/78] multiscope severity icon fixed: forgotten all scope added if selected group contains few scopes --- .../inspectionsTree/InspectionsConfigTreeTable.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java index 94ba8865d504..45f83ebbaf95 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java @@ -341,13 +341,6 @@ public class InspectionsConfigTreeTable extends TreeTable { if (myScopeToAverageSeverityMap.size() == 1) { return result; } - String[] scopesOrder = inspectionProfile.getScopesOrder(); - if (scopesOrder == null || scopesOrder.length == 0) { - final ArrayList scopesList = new ArrayList(myScopeToAverageSeverityMap.keySet()); - scopesList.remove(myDefaultScopeName); - ContainerUtil.sort(scopesList); - scopesOrder = ArrayUtil.toStringArray(scopesList); - } final SeverityAndOccurrences defaultSeveritiesAndOccurrences = myScopeToAverageSeverityMap.get(myDefaultScopeName); if (defaultSeveritiesAndOccurrences == null) { @@ -361,15 +354,15 @@ public class InspectionsConfigTreeTable extends TreeTable { } final int allInspectionsCount = defaultSeveritiesAndOccurrences.getOccurrencesSize(); final Map allScopes = defaultSeveritiesAndOccurrences.getOccurrences(); - String[] reversedScopesOrder = ArrayUtil.reverseArray(scopesOrder); - for (String currentScope : reversedScopesOrder) { + for (String currentScope : myScopeToAverageSeverityMap.keySet()) { final SeverityAndOccurrences currentSeverityAndOccurrences = myScopeToAverageSeverityMap.get(currentScope); if (currentSeverityAndOccurrences == null) { continue; } final HighlightSeverity currentSeverity = currentSeverityAndOccurrences.getPrimarySeverity(); if (currentSeverity == ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY || - currentSeverityAndOccurrences.getOccurrencesSize() == allInspectionsCount) { + currentSeverityAndOccurrences.getOccurrencesSize() == allInspectionsCount || + myDefaultScopeName.equals(currentScope)) { result.put(currentScope, currentSeverity); } else { From fa486fa98cc004f0c4c1416a9e66ad5f6eabdafe Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 29 Sep 2014 21:46:27 +0200 Subject: [PATCH 39/78] =?UTF-8?q?CR-IC-6404=20revert=20=E2=80=94=20Reverte?= =?UTF-8?q?d=20=E2=80=94=20state=20class=20must=20implement=20"equals".=20?= =?UTF-8?q?=E2=80=94=20yeah,=20dream=20about=20kotlin=20data=20classes=20I?= =?UTF-8?q?DEA-130435=20Project=20save=20fails:=20XmlSerializationExceptio?= =?UTF-8?q?n=20for=20SvnBranchConfigurationManager$ConfigurationBean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/xmlb/AbstractCollectionBinding.java | 7 ++-- .../com/intellij/util/xmlb/BeanBinding.java | 17 ++++------ .../util/xmlb/JDOMElementBinding.java | 9 +++--- .../com/intellij/util/xmlb/MapBinding.java | 21 ++++-------- .../intellij/util/xmlb/OptionTagBinding.java | 19 +++++------ .../util/xmlb/PrimitiveValueBinding.java | 3 -- .../com/intellij/util/xmlb/TagBinding.java | 5 +-- .../intellij/util/xmlb/TagBindingWrapper.java | 22 ++++++------- .../com/intellij/util/xmlb/TextBinding.java | 10 +++++- .../intellij/util/xmlb/XmlSerializerTest.java | 12 ++++++- .../plugins/xpathView/search/SearchScope.java | 32 ++++++++++++++++++- 11 files changed, 91 insertions(+), 66 deletions(-) diff --git a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java index 012437a96799..b0844695369a 100644 --- a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java @@ -115,11 +115,10 @@ abstract class AbstractCollectionBinding implements Binding { final String tagName = getTagName(o); if (tagName != null) { - if (ContainerUtil.isEmpty(collection)) { - return context == null ? new Element(tagName) : null; - } - Element result = new Element(tagName); + if (ContainerUtil.isEmpty(collection)) { + return new Element(tagName); + } for (Object e : collection) { if (e == null) { throw new XmlSerializationException("Collection " + myAccessor + " contains 'null' object"); diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index d0027edc0696..478462769023 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -76,11 +76,12 @@ class BeanBinding implements Binding { @Override @Nullable public Object serialize(@NotNull Object o, @Nullable Object context, SerializationFilter filter) { - return serializeInto(o, context == null ? new Element(myTagName) : null, filter); + Element element = new Element(myTagName); + serializeInto(o, element, filter); + return element; } - @Nullable - public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter) { + public void serializeInto(@NotNull Object o, @NotNull Element element, @NotNull SerializationFilter filter) { for (Binding binding : myPropertyBindingsList) { Accessor accessor = myPropertyBindings.get(binding); if (!filter.accepts(accessor, o)) continue; @@ -99,22 +100,16 @@ class BeanBinding implements Binding { } } - if (element == null) { - element = new Element(myTagName); - } - Object node = binding.serialize(o, element, filter); - if (node != null && node != element) { + if (node != null) { if (node instanceof org.jdom.Attribute) { - org.jdom.Attribute attr = (org.jdom.Attribute)node; - element.setAttribute(attr.getName(), attr.getValue()); + element.setAttribute((org.jdom.Attribute)node); } else { JDOMUtil.addContent(element, node); } } } - return element; } public void deserializeInto(final Object bean, @NotNull Element element) { diff --git a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java index 41ae99f8557f..825c184e935c 100644 --- a/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/JDOMElementBinding.java @@ -38,18 +38,19 @@ class JDOMElementBinding implements Binding { public Object serialize(Object o, Object context, SerializationFilter filter) { Object value = myAccessor.read(o); if (value == null) { - return context; + return null; } + if (value instanceof Element) { - Element targetElement; - targetElement = (Element)((Element)value).clone(); + Element targetElement = ((Element)value).clone(); + assert targetElement != null; targetElement.setName(myTagName); return targetElement; } if (value instanceof Element[]) { ArrayList result = new ArrayList(); for (Element element : ((Element[])value)) { - Element target = ((Element)element.clone()).setName(myTagName); + Element target = element.clone().setName(myTagName); result.add(target); } diff --git a/platform/util/src/com/intellij/util/xmlb/MapBinding.java b/platform/util/src/com/intellij/util/xmlb/MapBinding.java index 4c93669ccbe4..6783d88568e1 100644 --- a/platform/util/src/com/intellij/util/xmlb/MapBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/MapBinding.java @@ -31,7 +31,6 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Comparator; import java.util.Map; -import java.util.Set; import static com.intellij.util.xmlb.Constants.*; @@ -72,9 +71,7 @@ class MapBinding implements Binding { Element m = myMapAnnotation == null || myMapAnnotation.surroundWithTag() ? new Element(MAP) : (Element)context; assert m != null; - final Set keySet = map.keySet(); - final Object[] keys = ArrayUtil.toObjectArray(keySet); - + final Object[] keys = ArrayUtil.toObjectArray(map.keySet()); if (myMapAnnotation == null || myMapAnnotation.sortBeforeSave()) { Arrays.sort(keys, KEY_COMPARATOR); } @@ -89,7 +86,7 @@ class MapBinding implements Binding { if (kNode instanceof Text) { entry.setAttribute(getKeyAttributeName(), ((Text)kNode).getText()); } - else { + else if (kNode != null) { if (myMapAnnotation != null && !myMapAnnotation.surroundKeyWithTag()) { entry.addContent((Content)kNode); } @@ -104,7 +101,7 @@ class MapBinding implements Binding { if (vNode instanceof Text) { entry.setAttribute(getValueAttributeName(), ((Text)vNode).getText()); } - else { + else if (vNode != null) { if (myMapAnnotation != null && !myMapAnnotation.surroundValueWithTag()) { entry.addContent((Element)vNode); } @@ -116,7 +113,7 @@ class MapBinding implements Binding { } } - return m; + return m == context ? null : m; } private String getEntryAttributeName() { @@ -167,15 +164,12 @@ class MapBinding implements Binding { } else { if (myMapAnnotation != null && !myMapAnnotation.surroundKeyWithTag()) { - final Object[] children = JDOMUtil.getContent(entry); - for (Object child : children) { + for (Object child : JDOMUtil.getContent(entry)) { if (myKeyBinding.isBoundTo(child)) { k = myKeyBinding.deserialize(o, child); break; } } - - assert k != null : "no key found"; } else { final Object keyNode = entry.getChildren(getKeyAttributeName()).get(0); @@ -189,15 +183,12 @@ class MapBinding implements Binding { } else { if (myMapAnnotation != null && !myMapAnnotation.surroundValueWithTag()) { - final Object[] children = JDOMUtil.getContent(entry); - for (Object child : children) { + for (Object child : JDOMUtil.getContent(entry)) { if (myValueBinding.isBoundTo(child)) { v = myValueBinding.deserialize(o, child); break; } } - - assert v != null : "no value found"; } else { final Object valueNode = entry.getChildren(getValueAttributeName()).get(0); diff --git a/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java b/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java index 6eca99793aab..d7a14bb32dae 100644 --- a/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java @@ -74,19 +74,16 @@ class OptionTagBinding extends BasePrimitiveBinding { else { assert myBinding != null; Object node = myBinding.serialize(value, targetElement, filter); - if (node == null) { - return context == null ? targetElement : null; - } - - if (node instanceof Text) { - Text text = (Text)node; - targetElement.setAttribute(myValueAttribute, text.getText()); - } - else if (targetElement != node) { - JDOMUtil.addContent(targetElement, node); + if (node != null) { + if (node instanceof Text) { + Text text = (Text)node; + targetElement.setAttribute(myValueAttribute, text.getText()); + } + else if (targetElement != node) { + JDOMUtil.addContent(targetElement, node); + } } } - return targetElement; } diff --git a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java index f933695e9fa6..15ebb2d5c4b1 100644 --- a/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/PrimitiveValueBinding.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; @@ -37,8 +36,6 @@ class PrimitiveValueBinding implements Binding { @Override @Nullable public Object deserialize(Object o, @NotNull Object... nodes) { - assert nodes != null; - if (nodes.length == 0) { return convertString(""); } diff --git a/platform/util/src/com/intellij/util/xmlb/TagBinding.java b/platform/util/src/com/intellij/util/xmlb/TagBinding.java index 0743e247f2a2..289f9eeeb50b 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBinding.java @@ -48,10 +48,7 @@ class TagBinding extends BasePrimitiveBinding { assert myBinding != null; Object node = myBinding.serialize(value, v, filter); - if (node != v) { - if (node == null) { - return context == null ? v : null; - } + if (node != null && node != v) { JDOMUtil.addContent(v, node); } return v; diff --git a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java index 09f50d6e451a..389adca9cd18 100644 --- a/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java +++ b/platform/util/src/com/intellij/util/xmlb/TagBindingWrapper.java @@ -41,17 +41,17 @@ class TagBindingWrapper implements Binding { @Override public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) { Element e = new Element(myTagName); - Content n = (Content)binding.serialize(o, e, filter); - if (n == null) { - return null; - } - - String value = n.getValue(); - if (!myAttributeName.isEmpty()) { - e.setAttribute(myAttributeName, value); - } - else { - e.addContent(new Text(value)); + Content content = (Content)binding.serialize(o, e, filter); + if (content != null) { + if (!myAttributeName.isEmpty()) { + e.setAttribute(myAttributeName, content.getValue()); + } + else if (content instanceof Text) { + e.addContent(content); + } + else { + e.addContent(content.getValue()); + } } return e; } diff --git a/platform/util/src/com/intellij/util/xmlb/TextBinding.java b/platform/util/src/com/intellij/util/xmlb/TextBinding.java index c657c9f754d4..5cfaad76594d 100644 --- a/platform/util/src/com/intellij/util/xmlb/TextBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/TextBinding.java @@ -37,7 +37,15 @@ public class TextBinding implements Binding { return null; } Object node = myBinding.serialize(v, context, filter); - return node == null ? null : new Text(((Content)node).getValue()); + if (node == null) { + return null; + } + else if (node instanceof Text) { + return node; + } + else { + return new Text(((Content)node).getValue()); + } } @Override diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index eea800de8a2e..0f7217c5241e 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -126,6 +126,9 @@ public class XmlSerializerTest extends TestCase { BeanWithSubBean bean = new BeanWithSubBean(); doSerializerTest( "\n" + + " \n" + "

6#N0cM(#AUl97PSaysJ`} zQD9w)O`B%gB|Oy&H17&MvsN4dUu|=ka$YBWVn3&~zJl(ZnRw`WR-A#0YY(;( zMkbXV0#M73#14^dL_1y4_`4fFJ}pRU^CD$Ri4>H*$I=$#YXJLp%^w z!8J;`N?=W+Cm0R>(1=9=UwN%Vc4>A3f*8`~`M}Y_ zTB*2^)E)Y$Iip24XI+rmmkAtPT>5#(J`vn@l) z=S&Vym9`42#*E(Amm<)l;OZSxN19?9=R{Hn75!OcGw81zAdIyjA(cpym4K^b}>C zU{K+fO|$EEV{^u(QVB8IEXf2b@@GhG^aXY`$_ACQAmE5jNQ9iJs*Pfr{K3`kMzGzg z_EngB`4$~Q9Vm>n@^R$PklqtawQ#7q!pS3DW>V;wLs)-Eq}%zvdB;GPvwGnL``8Ka zk?3PjCB^%gg-)32=k_e6MXyz&B>GhxcQxaZdQ+sU4D^U#`jx7MW&CX%guLv08+q>h z6os>C;N?1dJOq95-f+ucwETdp*%n%|;m&`N{;JS&k=4e|!5!-yq;O$XP@=l^L6O+B zM`6I>t9>GwDObjYHLm_voxdjSkf`(D7)yie?6c~u@}8Jy*ZGQa^Lz9>>7ajK;p2nH z5gU1o(Z5qV^G@jm7T3q(^Pp?{R!yH+`&cgPig}odD)d}l`!xmFV*`R%5$wlYQXoAl zqI9^_9)|->g#~Lm(9_z3{pIEdE~?CW)$vo7kQ&*p*I;TP!{?hJYs%(7(W-LJ#zM%H zLrob-%%9_8^p1c7v^#Gx zmSr--ztV3Uy!X&VBkbKSf{QMFJU@*onB`ZPHGQ@>SyZrB#-WB09(nyU|+J2!aX-p+|BQ%E;D9hcFZBhDL@bCfu*7XOLj z8YQmr;u;~YY;n27m5EC>Rhy_v=(NN0rFtAFhHk$jwvbLg_ZxusyPH>E5d*_ZA_zK& zwQvxH(IX5VO=vz}oz$yfwKQQLDdVFVM5+P}ebMa#!?a zWfDL|lu+o5ziSIIt0epbTa$g!_eI)8H7&<8Y-K76rdkRze?e;*2e5DrhaBtHww-I6 zQJ#FD&F{qE82dtkiJ&Gzk#d@A9M;!hZ7jI5Z=Z<6_)?~)VY{c)+d9NZMze5FQ9t3e z1G95e(ol(obf=Nbx$nZ*l-$_J_f!)Hr&+o)11XgSUBQtS->E>}*A_In zgXzspu{3N}4oMSTH3)dH#{cR;t54vgJ0)Ls?-a@N;2b(f)C+cX>YTdEM&(dStou@2>w;B9$9iZnT<&6@=Yf5QO#DnY1oLM&g+J!O9prK_HBR7g_Df>W?M%G5ODmwtP8o}mBj8D6m(>{`IkbOzPb^t2y?(M7et0sm@mx+ zXr0o-TdeS#&5x=^6K}o3{BQA&-mCPBzY##?`=jjloUF7egX2u6N+d`BImdX-*Jw7K z)po@e5Bk$@|p>IzayJA?hPaoPoWlYVsVIpojA2tkK?WoGs#b^-o zSJ?Kb*|r5Ah@x$`GPXxl5GK=nVydczQFKg5nD**}P|@~fGTHB`<+sV3hQta2PED!I z3u)05IZKw_BQpf6I5QXmEndrvEn?yfSK3xjXI?+xm{fT3ZDj2@^gd-AP*w_!1IBNa zBXoMG(Yqm~xw`^u+}*jYmln44ZTxNXmD=34OWGW*!&`^Uol|hC;Uifi&y|i;YlmfD zF8z>Y|3PxVE^>;9i=nkn3(k6`@F#aYoh@|p)oJgw4biWJS{_|IC+|!{YTjELlak)g z>&JBz*MYqK!J%`5znOd}Z@+%WZu)MlVfM*4qCV^!ylKSRQqw!z#^__y-_*wx&shk^ z=F;03vPVPvou&sDZw95L@TO7ku;X1;0&#`$wqeJNcIP+S?=C(f z5u%4ff1PA>2Qd?YRU}2AGAR2$Z%}61gVG%zl-I*mL%YF9Q>~IZViVDkHb}NF(u0MW zE`w0wTwoAN%*aE85qnQt&l`YNC$hFeSe=1bS(X@ZryjNj0Y=u24ITuRWwn#~YUlV$HZnK#x7+}elWAVJm@ShA3#mTxwFxQv11!F zlnVmv(Y@&h`E>_}^6fnN4m;PflkXTu#rNduoXlj)^-l6@OYw@^LX>xV>Cs5*5ctET z??rOe`=v<7b&Mhr-27-FwsZyTDBe|*^uQR2qa!3(Nz2fzH1TKww&*0sWJ&mM# z31io%R^qqMW44I==~}5umfyU_s>*r^`U@+lDzzk*r}Fz!q*Dbx=r=!|AoZ5~e&-?m zT@vXLD^iCkAE87FQlCwiNMU{&x#|FceFgZhO8B$)iPVyA$9jR^k$}fhCjKSj|Csns zQ2w=|COj5AZtne&%tPHuf46-9$o>``-tzsQ_P6N9mhXq{Z&B|p-&^f((U>jY_4c>u z&6e*K)^|sz)8$)h85#@sLL7o@spx?Eo(ZV!i2hDn06J$Ct<2D z9L5!?Q(oRLl6u|e}94+84wkZ_+!KPl~vEFJKy z7SCSsJc=jCt`*gMQs;YrXyH^e;>q_?`&;zX$@d-hw`j?e?*jW<)Y8fK1p8Z*)5-Vc z_P400lkarvyCZuBnJ-nDUl3nsek?fMB%!9NetrSGA5~!glr#>-vFUsQ_&+A0V@$$cLMf2 zFje`i$cO1x)ZG$wy#)Jr6^yvYBd_DBMuRtUDDKRT?1?*bBR|2}u}fmrNG!?kapenQ zy^%-b&g@8=1T-b!3<7dhImt+i4E(Gcm&ofu;c{nG&tzU znhESL_*(V+Kwv(By{TZ5N2cVlOJF^TaC;@(5rO>#7{mRafB(e5KQZu64Ez%V|HQyQ zG4M|e{1XHJpJQNAu|vCJwnLl9GmWR1X9>@0o(((?@jSuv6wf}M*LmLM>E$`gGor|$ zUCnb7kDq5XPczTgd7k2Vf#(=cKhFsA%Hf&9Gn279jr9%1)m3`1q1xY2-B`U&C%_#=cg`=GH~A(zvU*id z$j!~gwPMAbc?)J1&RbDZROnw(Ry40@)}o@>0xvBqpLOS=!ElM#5L~C%-B+Dm-Oy0q zkgaJMh%GFdx1g-dg2<;}1*L^^=MO;cygB!#yo|I-*}-*HE7w+M>-E`n z>+1Bnsr%x;xo*stcmwsWUtdka_3Ikz!Ncn64Rxyqg|%^1y=i^*D!qEO!pr~`HNnq~ z3O_+|w8PvNT&vgVwGGu(tHIE!d(RL5`FOD-t*+9mC~iht)yj4C4flb7^$qoF8mjKg z)~g%tt6O(2o^w@wF4#WR>%d_By8GyZq(@nERedfPwyI%GPy#l_@tb>-;HhS9J=v{W zlfAyaZk?{W0g%+D;v&-umrKx63n2>#^-9hKot!$`jxL^8g8l5r@ zE|PwGWm+1eMJhFoF05UD{q@@PcrDje(Yu4z40Wr-w*F)uND2G2p*-T=&HLv(bE@@u zRgHQfU1USGzkYpiy(Td0yP|I0>iUgZDZ{dAP4&$BO-S%GRyRz(>H5`c*AAq+afeU) z7oHo(E}UODU*kP@elgziW+?J5Q*iH1h1zfT__TX?|0nN*y!Y^yKScG^pUfZkOfJ+$ z?)7O4p7Uuf&-=8G5Bjv5e(uv&@bvEXX{(>bSo2Fh?dD(lG@bZYzwFcc2-8n`r}#cZ z7B?Gg9gy0aImP`o-@G5W!l$`zDb&{I`?O;>gF_ze7SvM1ucL{O*mso3NF7HmhfBai3|F7|G)Ei`Q==Jps^>u5se*E92Y*N1M zJSFh$zwxH^y_t92x(!URtF!HR>+2htbk*vsY4c{SSTwh^NZ#`omloYQcb0;cE|_1m zsPN88fzMi0=`W&+%DrITyuw9%0WX|44}oUjGx(Xod&Tt=wd>{0Q!?$o`=&KEYODF1 zm|eIR}|^XoSx+zVFe^#U$qw-5&w2G;}| zS=??9t|bL|ud9}K;rfQUwY*EK8dlZvF0NkL5VYrk+pE?oC;3SF8tF=!8fi&7k_Pea zmoy~4#MOwSmC1U#8V^aYp-#CL)dm|HZCFM1>UGuj$D*L+Dy?6qe9MCNyGob18u2v3 zYlPDXqv5als~W1-1g-QJH&8L0vuf+sN`;D61*=xqH)w?oYnUIIeu4R`8-h}nS@mn{ z?^{_XAg#Q5UG)RO>b3GQyPkQvZdKK~>^rO12Uo7GTg94OAJl8J3u_vHOL%`36CJL3 z!A+pFKG?8E(reVKvhP$O$~M;N4^%g-ty;HQn-gR$VsMDdtjjK|Z=gBACB2JYCSi-#tyxPL3kGBk3kc}cW>&9VQy09Cd2v(Ss`^A)+RUoP zFMt-UY-9E6YQo7|;?G@0y(owMmg<1Zs&%UfTij5+P8zznZk-ClTgoNnt0Rd)LEs@3)PA>zgGqP16NU(Fa>S+$0uYK?-&N%z*X zz}oJr1WuJ-_8`CPL4IrNH&orrwl7%Spw~~L8S1t54U<;YT1|>OJK}I=YOB-S%bc%ztDl={@`VGu%Sw-kbp6G5`8ruu6k{DW7XOXY8)kC_PC0F)8O`) zX-JHjxZf%@E)@C_`K%f=_7dUjF&qD0S--Y!1N}b!%`PV~hSxJ(80l=$C$Ud?ppFqE z-Bn}HwXu2)ACuPIkGqj(8U$Nee=p52PFEWczf10Nb5@!1#*8W$eV=0cJRv%;Mj54b=%Zy{&HL%4&u5xWDwRxSIk) zj0~g&5)yv)SW@k^I;gLzos_7aCgV;Tl}Ru@+azF(Oe|G2yv*zIaE*2MtzTPLQ^%5! zfXR5bhkG0*Z=PB$fmqUr=c*b=bpcI_mu*nmCu%7;H|AWI=DA`2tyBg-VKC5t9&CrcU4#l{EY|Y;b)Bmv3-=2E!jA-X=S)T|D)YI_^3TE@^ZC^Fjxl z|0lS5>%8#C2yfajamW7#=bycG0MCQr)N-#n@LTun@Blo*rZ zK4>u7)yG6b6VsBlNwKjTjk@mdJ@;I=%nYMV{@CsAJ@dT$&OPV%zUMvfIRkg@ednV1 zjL$Y)vMpa{kH^#2tr6{k)~z0TRgggI)+}v?Nypj7UfFi44|^R!>|K(&+PblgFnm_x zqW4=LhgkIYwLT81E8P<|a%5X%b>O&GqrcrpkM%h=jXv#cqgl4)psp3Yf4;VOA9VWI zVcjm-*4T$%d(j?fePZ#sE0QI^`^tfKePJ6pvMrDfb9szvA3gS|9&Lf*%=6jp!{_%{ z3)&*_xz4vR|C|rM1NOUQ8`rg>k0aFtUawe;5ojEqhr@S#*vOG>F@4yp4q~s-#~#~g zmTlF2*lQ1BuhYjK+qfj#>ZS*tZxlY;`mQy{i{~4UK7C;u4%yb!hkq?-545l9pjQ@P ztbQ1v$!8q4@sex{q{BY(7^i&n*r!g}*3pL_CVX}eWRv}fL7%>`jd)#~_P12qM-d6B7HDWVf!?wC%#G$UKDs-Vt{Nj7RdSuK#q}B;xr(y z7q`_1v6l}Xmtr8>E0=n_F0DcI>ZM+z)N2B=AHSCR9P==w7P8GqpuRAVk2Tc#n9CCD z!{`3jCn;h+Y&SnZKXce#yY%an^n>ly2jO?=czc8JOoP>U4urjqAiQYs*pE1gHi;gI zMG`9{)&hB**w1+6ECwoUuSv(t55ha7b?SI81>r?}uV){f3c`y8kNr#l@?5M^ zkJrnDIR*9#8T6`OW*uALZwFKcs4(YMi z8H6`Q$1^?D_x$rEkKd>9L3p*`@w`_9Ilk+q9>=#Vh~6&nxa^k5=QUi|7UKv=I<9ML zh0m9`==<;GYuqU8V-v=zhG>5yc1hh9v}tiBvuZ;q>3*=yHtBZ=+GB$7I>6((>BnMI z|9MPdpjhZ?5V-Q~09XFg>&_(eKi zaS&dWXAtVNKX;zDnwridzA}tak*P-tI%?bE3nH$ z-QJ4K`NbkaMcs}h%`HJf0)3yy#x1DI5*b6x?)lI@=@i|=hXrpMu9rgN6%lEBPsV~< z+*&QS(7*Q4lTGi3X3s71T8j%7cuG?_>mqScg_mw&`~HR~EO2`^(LA1?y8hNuBrhOW zfw}IABDpE(4nAgYJ&Ve`F>TQwW1f3dD;da4VI%a4dThl_9&tR3XTiA?B1MD0x`?>2KQ2!G;Jd;H z#7=SXr0I38^F?c#zfHiAmatu2bf2T7lFIU89x1VM_H4W< z@Tf2Nmc{qVou!2Zh{&7TvGBHFj+aIVZ$+=V2(%FQJ1gh87vbK?JXHlv)7uJpAj=?=+7)VmEIgsmz>~mJ3LU{` zxmjn>57Ek>6BIhOQlY>8QlT$$dfFdb)l@6vqG|@f3psc*Ol&Lfgd12lXWV_lpLy#!VlVwXCXV0;tjvAjXc?!xO$xhF< zS8+eil+-hMJ~84mbN*<8!bCZ)+K)3dU7N_=f<0SevO1E>ZE>Z@K}XypOwc&9C9C`U z1`56hple5pXI>#rJQbvdql@MtEs7H>@mUHde^IlMaW3X#g)gJ=Sqmr6#B&$}saU`n zYecgPO3JySw_AZz(7d@gTZK{nJk301wt@EOGZ*C>j#8UI{1za6*5ZR2qpoUmN1GPFG)vx^_=| zm9D;8SFhLA*XZhNb@iup^?n$GuLp-iRzSqH3>=tH=fc-tqDSL?Iq*_6J_`ZcfXr_O zGH(fR5YP!642%JO4|sJH?kNHf0eNvY0EYpKfWv`ffP8JVKae-*MZ{+j@EmY4@C5KG zupP)3Qd@u>ZdEP;S=e7LUFg36F^UlZBLYSQj0hMJFd|??z=(hm0V4uN1dIq65ilZP zM8JrE5dk9tMg)uq7!fccU_`)(fDr*B0!9Rk2pADCBJlSg0g)e|OUM{jft&*fQIy{+ z22X-iU;cgmEe_;51bfwz|Eo8@hI(EhbaOAgg{9Q<3Pond&Ac@IsK5WE{nj(!ZNd3I zjQQ&=!X9G?H)usme9?}9oCBk$=(vpux;SvFI}|s9<*`U@sWy~x2ssQse@CeNO_`KU^Dn{Z9Tm; zO6~UhS@U0NlOl1?P4X?0|0?+JZ8^7P7=5~>bIVWqw*SOtp)nl^Z_`iz^mG*Eo&Lwu z6aD$ePo3?!jBlSjp?RiK_0kDZs)jjJFgobTja4-9=m|7lOfyP60?D9e+God zE`hL}d5|bb8H97<7C_ino(J=*A?$OF#HB#)Uk2g+S_s=&1GyivQ66swvVYqkJl;+S z^In6ne@7wQe-gs|kq8RMr@J(TD&6(g0X_Av!@BFrhKTOE>+RdS>(LhnYxU}NjdyDG zsD1l~s`dT{4i8@y$Mwyhw;dgR@OYXM)wOX?*$dsGRPJL%)!t#x4bFa_b(X~0M#j}0I0|m#fEzezkYV^#XU;bdubI)A*^1cIG zT4$cAp6@*TtMyU;5}J{JXmlm!OGny{$bV6F#r){h@RM81_{Sx4Zc)NV=_}XIAH3|Z z=C_ZJ@echs=dRa|T`;%bKB_i(c=E1yc79=2cDy>b=Z%KR_UG?@ z`Mm~n^r&|~-uFhrgo5RZ%>|h=-g@F?_maWC$upn)V*JWm_OJcf9an7TX!G{ZCU3v* zKb~yuYMJuKD`Gp^FPgTPL*ansU$2kHs%d zUcZ;FolN+!E+=gG%blM*wWD9cyS4Vjfv^6e@_`S=Jviyn5$})sVB!}k^|_OG{PX^n z?9X3W4BDBo$u{FP)0ojI=f?gxF5UgY(MLwFp3#3>%h`jEU+H}J?u~z} z%gtUh<$!D1y^(3tytA$?Tm9lK4UZ2xH}>qNqwlx&KeOXhIOl`v^Mvu7*}Pc=LkF(pS}I zRnEQ%4+8l=8|mOTqwO14ecY0L;+Fh3#O+49H;UUg)z{|zP4#=?9^68R&wi87c+V5h zc$Yg%zb^ckWIQ2VxzWBAiSvq@MXzm8y`4OKO%jhk^kHx`efK}U0FYN!S)tgn%+Yc; zVngKN3#$tXDoPgw-&fkuf$f&@fwSPd`)W5Z9OD+2N?~mG$x~3hk2h_{$14$@-YD z6l#?9H!moZzf84b`hkTaAYqXH5Q1F2AG!FDE=VV&19Ae=3Tc7thP(vX1!;zCgET=l zKpG(pkb1}pNFAgWvIJ5FDTd@jn4bf2K^%}NkT^&TWCSDJM(B-RZ|2h?B+G!q^Ac->cXQHoJu`0xg*yKklt6 zcQSMT1dcrodqr^Fe%x@CE7q-*x$d++=N6%Ib^cnZ1v*wd?B6$L;U=titUeCOv>V)H zPpTg`Lgni0x~ZA%I{eondYPxf-CBDsXcxNfb9pEK&Df4_CP&zN)`ADgqb(OT^FL@F+YswO7ot zCxgWD?(>Es00n(n`M!ehYgHMb11f$Oqo`1>#h+(P}jVb6eT$w>C+;%z;t zm%m9A3$ERo>CcS=x0k<8ieY~p0sM^zx0k;&C<@$6Jip&>pG^U`m%q6*1YB1DZbZbe zh=Hab_m2o0+rMA`2$LynWLVW0*v0po%7Dp<8B`3kI?^bgG1pExvfUw30j4=^6bE!n zOQsk;&UI3>#7H3PM@S@~3w!et-q-G|Y19eieexl2T6zYx$>SDzybI{@q*ERA*q;qJ zW?TVeKWov>SQpFh>rASUm@m;I5PKY$=1e3-99wA$FxTOrc!4Pt3$!}iG(xtA$>WRT znU_KxK&!(;?LfA(56I)aBoKcm1Ujifpp~ixCQ^mK6e<$fzaa{?3Tgg_^?2u!D40k)lc+=>_J_b^vI%rhoWN9y z7MMmRfhj}+E%Ya>pWU5H9}3K%R)LwcSKtiVCNPT{fbOg$S^>1#-C{r3(~`yd^Ey;B zkFiX>X4-Y(`gNDv!@u&sadFwcoqoe|oR2`b@MjpkBfiJ@-%n3=HmF>Ue>W-#kX%R= zWIbdLpTeI>pTk~>ma)!$02`#n7|tkNrjX^jABH - initial API and implementation + ******************************************************************************/ +package com.jetbrains.python.internal; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import com.jetbrains.python.internal.linux.ProcessListLinux; +import com.jetbrains.python.internal.macos.ProcessListMac; +import com.jetbrains.python.internal.win32.ProcessListWin32; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +public class ProcessUtils { + private static final Logger LOG = Logger.getInstance(ProcessUtils.class); + + /** + * Passes the commands directly to Runtime.exec (with the passed envp) + */ + 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. + */ + private static String[] getWithoutEmptyParams(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 list.toArray(new String[list.size()]); + } + + + public static IProcessList getProcessList(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 PyProcessInfo[] getProcessList() { + return new PyProcessInfo[0]; + } + }; + } +} diff --git a/python/pydevSrc/com/jetbrains/python/internal/PyProcessInfo.java b/python/pydevSrc/com/jetbrains/python/internal/PyProcessInfo.java new file mode 100644 index 000000000000..69ff84b2fbcf --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/PyProcessInfo.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * 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: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package com.jetbrains.python.internal; + +import com.google.common.base.Joiner; + +/** + * @author traff + */ +public class PyProcessInfo { + + private final int myPid; + private final String myCommand; + private final String myArgs; + + public PyProcessInfo(String pidString, String name) { + this(Integer.parseInt(pidString), name); + } + + public PyProcessInfo(int pid, String name) { + myPid = pid; + String[] args = name.split(" "); + myCommand = args.length > 0 ? args[0] : ""; + myArgs = name; + } + + public int getPid() { + return myPid; + } + + public String getCommand() { + return myCommand; + } + + @Override + public String toString() { + return Joiner.on("").join(String.valueOf(myPid), " (", myArgs, ")"); + } + + public String getArgs() { + return myArgs; + } +} \ No newline at end of file diff --git a/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java b/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java new file mode 100644 index 000000000000..edada5cf09aa --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 QNX Software Systems and others. + * 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: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package com.jetbrains.python.internal.linux; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; + +import com.intellij.openapi.util.io.FileUtil; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.IProcessList; +import com.jetbrains.python.internal.PyProcessInfo; + +/** + * Use through PlatformUtils. + */ +public class ProcessListLinux implements IProcessList { + + PyProcessInfo[] empty = new PyProcessInfo[0]; + + public ProcessListLinux() { + } + + /** + * Insert the method's description here. + * + * @see IProcessList#getProcessList + */ + public PyProcessInfo[] getProcessList() { + File proc = new File("/proc"); //$NON-NLS-1$ + File[] pidFiles = null; + + // We are only interested in the pid so filter the rest out. + try { + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String name) { + boolean isPID = false; + try { + Integer.parseInt(name); + isPID = true; + } + catch (NumberFormatException e) { + } + return isPID; + } + }; + pidFiles = proc.listFiles(filter); + } + catch (SecurityException e) { + } + + PyProcessInfo[] processInfo = empty; + if (pidFiles != null) { + processInfo = new PyProcessInfo[pidFiles.length]; + for (int i = 0; i < pidFiles.length; i++) { + File cmdLine = new File(pidFiles[i], "cmdline"); //$NON-NLS-1$ + String name; + try { + name = FileUtil.loadFile(cmdLine).replace('\0', ' '); + } + catch (IOException e) { + name = ""; + } + if (name.length() == 0) { + name = "Unknown"; //$NON-NLS-1$ + } + processInfo[i] = new PyProcessInfo(pidFiles[i].getName(), name); + } + } + else { + pidFiles = new File[0]; + } + return processInfo; + } +} \ No newline at end of file diff --git a/python/pydevSrc/com/jetbrains/python/internal/macos/ProcessListMac.java b/python/pydevSrc/com/jetbrains/python/internal/macos/ProcessListMac.java new file mode 100644 index 000000000000..da670bd17a8a --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/macos/ProcessListMac.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2005, 2010 IBM Corporation and others. + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.jetbrains.python.internal.macos; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.List; + +import com.google.common.collect.Lists; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.IProcessList; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.ProcessUtils; + +/** + * Use through PlatformUtils. + */ +public class ProcessListMac implements IProcessList { + + PyProcessInfo[] empty = new PyProcessInfo[0]; + + public ProcessListMac() { + } + + /** + * Insert the method's description here. + * @see IProcessList#getProcessList + */ + public PyProcessInfo[] getProcessList() { + Process ps; + BufferedReader psOutput; + String[] args = { "/bin/ps", "-a", "-x", "-o", "pid,command" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + + try { + ps = ProcessUtils.createProcess(args, null, null); + psOutput = new BufferedReader(new InputStreamReader(ps.getInputStream())); + } catch (Exception e) { + return new PyProcessInfo[0]; + } + + //Read the output and parse it into an array list + List procInfo = Lists.newArrayList(); + + try { + String lastline; + while ((lastline = psOutput.readLine()) != null) { + //The format of the output should be + //PID space name + lastline = lastline.trim(); + int index = lastline.indexOf(' '); + if (index != -1) { + String pidString = lastline.substring(0, index).trim(); + try { + int pid = Integer.parseInt(pidString); + String arg = lastline.substring(index + 1); + procInfo.add(new PyProcessInfo(pid, arg)); + } catch (NumberFormatException e) { + } + } + } + psOutput.close(); + } catch (Exception e) { + /* Ignore */ + } + + ps.destroy(); + return procInfo.toArray(new PyProcessInfo[procInfo.size()]); + } +} \ No newline at end of file diff --git a/python/pydevSrc/com/jetbrains/python/internal/win32/CSVReader.java b/python/pydevSrc/com/jetbrains/python/internal/win32/CSVReader.java new file mode 100644 index 000000000000..0cebb2487d1f --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/win32/CSVReader.java @@ -0,0 +1,247 @@ +// From: http://www.halley.cc/code/?java/CSVReader.java + +/** + Copyright 2005 Bytecode Pty Ltd. + + 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.jetbrains.python.internal.win32; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +/** + * A very simple CSV reader released under a commercial-friendly license. + * + * @author Glen Smith + * + */ +public class CSVReader { + + private BufferedReader br; + + private boolean hasNext = true; + + private char separator; + + private char quotechar; + + private int skipLines; + + private boolean linesSkiped; + + /** The default separator to use if none is supplied to the constructor. */ + public static final char DEFAULT_SEPARATOR = ','; + + /** + * The default quote character to use if none is supplied to the + * constructor. + */ + public static final char DEFAULT_QUOTE_CHARACTER = '"'; + + /** + * The default line to start reading. + */ + public static final int DEFAULT_SKIP_LINES = 0; + + /** + * Constructs CSVReader using a comma for the separator. + * + * @param reader + * the reader to an underlying CSV source. + */ + public CSVReader(Reader reader) { + this(reader, DEFAULT_SEPARATOR); + } + + /** + * Constructs CSVReader with supplied separator. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries. + */ + public CSVReader(Reader reader, char separator) { + this(reader, separator, DEFAULT_QUOTE_CHARACTER); + } + + /** + * Constructs CSVReader with supplied separator and quote char. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + */ + public CSVReader(Reader reader, char separator, char quotechar) { + this(reader, separator, quotechar, DEFAULT_SKIP_LINES); + } + + /** + * Constructs CSVReader with supplied separator and quote char. + * + * @param reader + * the reader to an underlying CSV source. + * @param separator + * the delimiter to use for separating entries + * @param quotechar + * the character to use for quoted elements + * @param line + * the line number to skip for start reading + */ + public CSVReader(Reader reader, char separator, char quotechar, int line) { + this.br = new BufferedReader(reader); + this.separator = separator; + this.quotechar = quotechar; + this.skipLines = line; + } + + /** + * Reads the entire file into a List with each element being a String[] of + * tokens. + * + * @return a List of String[], with each String[] representing a line of the + * file. + * + * @throws IOException + * if bad things happen during the read + */ + public List readAll() throws IOException { + + List allElements = new ArrayList(); + while (hasNext) { + String[] nextLineAsTokens = readNext(); + if (nextLineAsTokens != null) { + allElements.add(nextLineAsTokens); + } + } + return allElements; + + } + + /** + * Reads the next line from the buffer and converts to a string array. + * + * @return a string array with each comma-separated element as a separate + * entry. + * + * @throws IOException + * if bad things happen during the read + */ + public String[] readNext() throws IOException { + + String nextLine = getNextLine(); + return hasNext ? parseLine(nextLine) : null; + } + + /** + * Reads the next line from the file. + * + * @return the next line from the file without trailing newline + * @throws IOException + * if bad things happen during the read + */ + private String getNextLine() throws IOException { + if (!this.linesSkiped) { + for (int i = 0; i < skipLines; i++) { + br.readLine(); + } + this.linesSkiped = true; + } + String nextLine = br.readLine(); + if (nextLine == null) { + hasNext = false; + } + return hasNext ? nextLine : null; + } + + /** + * Parses an incoming String and returns an array of elements. + * + * @param nextLine + * the string to parse + * @return the comma-tokenized list of elements, or null if nextLine is null + * @throws IOException if bad things happen during the read + */ + public String[] parseLine(String nextLine) throws IOException { + + if (nextLine == null) { + return null; + } + + List tokensOnThisLine = new ArrayList(); + StringBuffer sb = new StringBuffer(); + boolean inQuotes = false; + do { + if (inQuotes) { + // continuing a quoted section, reappend newline + sb.append("\n"); + nextLine = getNextLine(); + if (nextLine == null) { + break; + } + } + for (int i = 0; i < nextLine.length(); i++) { + + char c = nextLine.charAt(i); + if (c == quotechar) { + // this gets complex... the quote may end a quoted block, or escape another quote. + // do a 1-char lookahead: + if (inQuotes // we are in quotes, therefore there can be escaped quotes in here. + && nextLine.length() > (i + 1) // there is indeed another character to check. + && nextLine.charAt(i + 1) == quotechar) { // ..and that char. is a quote also. + // we have two quote chars in a row == one quote char, so consume them both and + // put one on the token. we do *not* exit the quoted text. + sb.append(nextLine.charAt(i + 1)); + i++; + } else { + inQuotes = !inQuotes; + // the tricky case of an embedded quote in the middle: a,bc"d"ef,g + if (i > 2 //not on the begining of the line + && nextLine.charAt(i - 1) != this.separator //not at the begining of an escape sequence + && nextLine.length() > (i + 1) && + nextLine.charAt(i + 1) != this.separator //not at the end of an escape sequence + ) { + sb.append(c); + } + } + } else if (c == separator && !inQuotes) { + tokensOnThisLine.add(sb.toString()); + sb = new StringBuffer(); // start work on next token + } else { + sb.append(c); + } + } + } while (inQuotes); + tokensOnThisLine.add(sb.toString()); + return tokensOnThisLine.toArray(new String[0]); + + } + + /** + * Closes the underlying reader. + * + * @throws IOException if the close fails + */ + public void close() throws IOException { + br.close(); + } + +} \ No newline at end of file diff --git a/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32.java b/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32.java new file mode 100644 index 000000000000..5b91312424e2 --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2014 Brainwy Software Ltda. + * 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 + *******************************************************************************/ +package com.jetbrains.python.internal.win32; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Joiner; +import com.intellij.openapi.diagnostic.Logger; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.IProcessList; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.ProcessUtils; + +/* + * This implementation uses the tasklist.exe from windows (must be on the path). + * + * Use through PlatformUtils. + */ +public class ProcessListWin32 implements IProcessList { + private static final Logger LOG = Logger.getInstance(ProcessListWin32.class); + private String myHelpersRoot; + + public ProcessListWin32(String helpersRoot) { + + myHelpersRoot = helpersRoot; + } + + public PyProcessInfo[] getProcessList() { + + try { + return createFromWMIC(); + } + catch (Exception e) { + //Keep on going for other alternatives + } + + Process p = null; + InputStream in = null; + PyProcessInfo[] procInfos = new PyProcessInfo[0]; + + try { + + try { + try { + p = ProcessUtils.createProcess(new String[]{"tasklist.exe", "/fo", "csv", "/nh", "/v"}, null, + null); + } + catch (Exception e) { + //Use fallback + return new ProcessListWin32Internal(myHelpersRoot).getProcessList(); + } + in = p.getInputStream(); + InputStreamReader reader = new InputStreamReader(in); + procInfos = parseListTasks(reader); + } + finally { + if (in != null) { + in.close(); + } + if (p != null) { + p.destroy(); + } + } + } + catch (IOException e) { + } + return procInfos; + } + + private PyProcessInfo[] createFromWMIC() throws Exception { + Process p = ProcessUtils.createProcess(new String[]{"wmic.exe", "path", "win32_process", "get", + "Caption,Processid,Commandline"}, null, + null); + List lst = new ArrayList(); + InputStream in = p.getInputStream(); + InputStreamReader reader = new InputStreamReader(in); + try { + BufferedReader br = new BufferedReader(reader); + String line = br.readLine(); + //We should have something as: Caption CommandLine ProcessId + //From this we get the number of characters for each column + int commandLineI = line.indexOf("CommandLine"); + int processIdI = line.indexOf("ProcessId"); + if (commandLineI == -1) { + throw new AssertionError("Could not find CommandLine in: " + line); + } + if (processIdI == -1) { + throw new AssertionError("Could not find ProcessId in: " + line); + } + + while (true) { + line = br.readLine(); + if (line == null) { + break; + } + if (line.trim().length() == 0) { + continue; + } + String name = line.substring(0, commandLineI).trim(); + String commandLine = line.substring(commandLineI, processIdI).trim(); + String processId = line.substring(processIdI, line.length()).trim(); + lst.add(new PyProcessInfo(Integer.parseInt(processId), name + " " + commandLine)); + } + if (lst.size() == 0) { + throw new AssertionError("Error: no processes found"); + } + return lst.toArray(new PyProcessInfo[0]); + } + catch (Exception e) { + LOG.error(e); + throw e; + } + finally { + in.close(); + } + } + + public PyProcessInfo[] parseListTasks(InputStreamReader reader) { + BufferedReader br = new BufferedReader(reader); + CSVReader csvReader = new CSVReader(br); + List processList = new ArrayList(); + String[] next; + do { + try { + next = csvReader.readNext(); + if (next != null) { + int pid = Integer.parseInt(next[1]); + String name = Joiner.on(" - ").join(next[0], next[next.length - 1]); + processList.add(new PyProcessInfo(pid, name)); + } + } + catch (IOException e) { + break; + } + } + while (next != null); + + return processList.toArray(new PyProcessInfo[processList.size()]); + } +} \ No newline at end of file diff --git a/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32Internal.java b/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32Internal.java new file mode 100644 index 000000000000..0ee7c9098da9 --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/internal/win32/ProcessListWin32Internal.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2000, 2014 QNX Software Systems and others. + * 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: + * QNX Software Systems - Initial API and implementation + * Martin Oberhuber (Wind River) - [303083] Split out the Spawner + *******************************************************************************/ +package com.jetbrains.python.internal.win32; + +import com.google.common.collect.Lists; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.IProcessList; +import com.jetbrains.python.internal.PyProcessInfo; +import com.jetbrains.python.internal.ProcessUtils; + +import java.io.*; +import java.util.List; + +/* + * This implementation uses a listtasks which is shipped together (so, it should always work on windows). + * + * Use through PlatformUtils. + */ +public class ProcessListWin32Internal implements IProcessList { + + private PyProcessInfo[] NOPROCESS = new PyProcessInfo[0]; + private String myHelpersRoot; + + public ProcessListWin32Internal(String helpersRoot) { + + myHelpersRoot = helpersRoot; + } + + public PyProcessInfo[] getProcessList() { + Process p = null; + String command = null; + InputStream in = null; + PyProcessInfo[] procInfos = NOPROCESS; + + try { + File file = new File(myHelpersRoot, "process/listtasks.exe"); + + + //TODO: use listtasks.exe + //IPath relative = new Path("com/jetbrains/python/internal/win32").addTrailingSeparator().append("listtasks.exe"); + //file = BundleUtils.getRelative(relative, bundle); + + if (file != null && file.exists()) { + command = file.getCanonicalPath(); + if (command != null) { + try { + p = ProcessUtils.createProcess(new String[]{command}, null, null); + in = p.getInputStream(); + InputStreamReader reader = new InputStreamReader(in); + procInfos = parseListTasks(reader); + } + finally { + if (in != null) { + in.close(); + } + if (p != null) { + p.destroy(); + } + } + } + } + } + catch (IOException e) { + } + return procInfos; + } + + public PyProcessInfo[] parseListTasks(InputStreamReader reader) { + BufferedReader br = new BufferedReader(reader); + List processList = Lists.newArrayList(); + try { + String line; + while ((line = br.readLine()) != null) { + int tab = line.indexOf('\t'); + if (tab != -1) { + String proc = line.substring(0, tab).trim(); + String name = line.substring(tab).trim(); + if (proc.length() > 0 && name.length() > 0) { + try { + int pid = Integer.parseInt(proc); + processList.add(new PyProcessInfo(pid, name)); + } + catch (NumberFormatException e) { + } + } + } + } + } + catch (IOException e) { + } + return processList.toArray(new PyProcessInfo[processList.size()]); + } +} \ No newline at end of file diff --git a/python/python-pydev.iml b/python/python-pydev.iml index 4b66a64b39f8..4f1b6190919b 100644 --- a/python/python-pydev.iml +++ b/python/python-pydev.iml @@ -11,6 +11,7 @@ + diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index ea492e43cf2d..b8385d4633cb 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -309,7 +309,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr } protected String getConnectionMessage() { - return "Connecting to debugger..."; + return "Waiting for connection..."; } protected String getConnectionTitle() { @@ -730,7 +730,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr return XDebuggerBundle.message("debugger.state.message.connected"); } else { - return "Waiting for connection..."; + return getConnectionMessage(); } } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index 583641e53edf..8f1a1eb7d7af 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -118,7 +118,7 @@ public class PyDebugRunner extends GenericProgramRunner { return -1; } - protected static void createConsoleCommunicationAndSetupActions(@NotNull final Project project, + public static void createConsoleCommunicationAndSetupActions(@NotNull final Project project, @NotNull final ExecutionResult result, @NotNull PyDebugProcess debugProcess) { ExecutionConsole console = result.getExecutionConsole(); diff --git a/python/src/com/jetbrains/python/run/PythonConfigurationType.java b/python/src/com/jetbrains/python/run/PythonConfigurationType.java index 0821452b3103..0bab1a338db7 100644 --- a/python/src/com/jetbrains/python/run/PythonConfigurationType.java +++ b/python/src/com/jetbrains/python/run/PythonConfigurationType.java @@ -37,7 +37,7 @@ public class PythonConfigurationType implements ConfigurationType { return ConfigurationTypeUtil.findConfigurationType(PythonConfigurationType.class); } - private static class PythonConfigurationFactory extends PythonConfigurationFactoryBase { + public static class PythonConfigurationFactory extends PythonConfigurationFactoryBase { protected PythonConfigurationFactory(ConfigurationType configurationType) { super(configurationType); } From 71ab64f47e4947e19ac2aeca88cfd75cacdcedb3 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 29 Sep 2014 21:28:43 +0400 Subject: [PATCH 43/78] cosmetic: sync button title with "Autoscroll from/to Source" in project view --- .../codeInsight/documentation/DocumentationManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index c5828145c991..99900deda597 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -115,17 +115,17 @@ public class DocumentationManager extends DockablePopupManager Date: Tue, 30 Sep 2014 05:23:41 +0400 Subject: [PATCH 44/78] GPUB: sync with GK 1.2 --- .../lang/parser/GeneratedParserUtilBase.java | 411 +++++++++--------- 1 file changed, 217 insertions(+), 194 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java index 8ad37418f660..830b2697aa97 100644 --- a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java +++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java @@ -86,174 +86,174 @@ public class GeneratedParserUtilBase { } }; - public static boolean eof(PsiBuilder builder_, int level_) { - return builder_.eof(); + public static boolean eof(PsiBuilder builder, int level) { + return builder.eof(); } - public static int current_position_(PsiBuilder builder_) { - return builder_.rawTokenIndex(); + public static int current_position_(PsiBuilder builder) { + return builder.rawTokenIndex(); } - public static boolean recursion_guard_(PsiBuilder builder_, int level_, String funcName_) { - if (level_ > MAX_RECURSION_LEVEL) { - builder_.error("Maximum recursion level (" + MAX_RECURSION_LEVEL + ") reached in '" + funcName_ + "'"); + public static boolean recursion_guard_(PsiBuilder builder, int level, String funcName) { + if (level > MAX_RECURSION_LEVEL) { + builder.error("Maximum recursion level (" + MAX_RECURSION_LEVEL + ") reached in '" + funcName + "'"); return false; } return true; } - public static boolean empty_element_parsed_guard_(PsiBuilder builder_, String funcName_, int prev_position_) { - if (prev_position_ == current_position_(builder_)) { - builder_.error("Empty element parsed in '" + funcName_ + "' at offset " + builder_.getCurrentOffset()); + public static boolean empty_element_parsed_guard_(PsiBuilder builder, String funcName, int pos) { + if (pos == current_position_(builder)) { + builder.error("Empty element parsed in '" + funcName + "' at offset " + builder.getCurrentOffset()); return false; } return true; } - public static boolean invalid_left_marker_guard_(PsiBuilder builder_, PsiBuilder.Marker marker_, String funcName_) { - //builder_.error("Invalid left marker encountered in " + funcName_ +" at offset " + builder_.getCurrentOffset()); - boolean goodMarker = marker_ != null; // && ((LighterASTNode)marker_).getTokenType() != TokenType.ERROR_ELEMENT; + public static boolean invalid_left_marker_guard_(PsiBuilder builder, PsiBuilder.Marker marker, String funcName) { + //builder.error("Invalid left marker encountered in " + funcName_ +" at offset " + builder.getCurrentOffset()); + boolean goodMarker = marker != null; // && ((LighterASTNode)marker).getTokenType() != TokenType.ERROR_ELEMENT; if (!goodMarker) return false; - ErrorState state = ErrorState.get(builder_); + ErrorState state = ErrorState.get(builder); return !state.frameStack.isEmpty(); } - public static TokenSet create_token_set_(IElementType... tokenTypes_) { - return TokenSet.create(tokenTypes_); + public static TokenSet create_token_set_(IElementType... tokenTypes) { + return TokenSet.create(tokenTypes); } - public static boolean leftMarkerIs(PsiBuilder builder_, IElementType type) { - LighterASTNode marker = builder_.getLatestDoneMarker(); + public static boolean leftMarkerIs(PsiBuilder builder, IElementType type) { + LighterASTNode marker = builder.getLatestDoneMarker(); return marker != null && marker.getTokenType() == type; } - - private static boolean consumeTokens(PsiBuilder builder_, boolean smart, int pin, IElementType... tokens) { - ErrorState state = ErrorState.get(builder_); + + private static boolean consumeTokens(PsiBuilder builder, boolean smart, int pin, IElementType... tokens) { + ErrorState state = ErrorState.get(builder); if (state.completionState != null && state.predicateCount == 0) { - addCompletionVariant(builder_, state.completionState, tokens); + addCompletionVariant(builder, state.completionState, tokens); } // suppress single token completion CompletionState completionState = state.completionState; state.completionState = null; - boolean result_ = true; - boolean pinned_ = false; + boolean result = true; + boolean pinned = false; for (int i = 0, tokensLength = tokens.length; i < tokensLength; i++) { - if (pin > 0 && i == pin) pinned_ = result_; - if (result_ || pinned_) { + if (pin > 0 && i == pin) pinned = result; + if (result || pinned) { boolean fast = smart && i == 0; - if (!(fast ? consumeTokenFast(builder_, tokens[i]) : consumeToken(builder_, tokens[i]))) { - result_ = false; - if (pin < 0 || pinned_) report_error_(builder_, state, false); + if (!(fast ? consumeTokenFast(builder, tokens[i]) : consumeToken(builder, tokens[i]))) { + result = false; + if (pin < 0 || pinned) report_error_(builder, state, false); } } } state.completionState = completionState; - return pinned_ || result_; + return pinned || result; } - public static boolean consumeTokens(PsiBuilder builder_, int pin_, IElementType... token) { - return consumeTokens(builder_, false, pin_, token); + public static boolean consumeTokens(PsiBuilder builder, int pin, IElementType... token) { + return consumeTokens(builder, false, pin, token); } - public static boolean consumeTokensSmart(PsiBuilder builder_, int pin_, IElementType... token) { - return consumeTokens(builder_, true, pin_, token); + public static boolean consumeTokensSmart(PsiBuilder builder, int pin, IElementType... token) { + return consumeTokens(builder, true, pin, token); } - public static boolean parseTokens(PsiBuilder builder_, int pin_, IElementType... tokens) { - return parseTokens(builder_, false, pin_, tokens); + public static boolean parseTokens(PsiBuilder builder, int pin, IElementType... tokens) { + return parseTokens(builder, false, pin, tokens); } - public static boolean parseTokensSmart(PsiBuilder builder_, int pin_, IElementType... tokens) { - return parseTokens(builder_, true, pin_, tokens); + public static boolean parseTokensSmart(PsiBuilder builder, int pin, IElementType... tokens) { + return parseTokens(builder, true, pin, tokens); } - public static boolean parseTokens(PsiBuilder builder_, boolean smart, int pin_, IElementType... tokens) { - PsiBuilder.Marker marker_ = builder_.mark(); - boolean result_ = consumeTokens(builder_, smart, pin_, tokens); - if (!result_) { - marker_.rollbackTo(); + public static boolean parseTokens(PsiBuilder builder, boolean smart, int pin, IElementType... tokens) { + PsiBuilder.Marker marker = builder.mark(); + boolean result = consumeTokens(builder, smart, pin, tokens); + if (!result) { + marker.rollbackTo(); } else { - marker_.drop(); + marker.drop(); } - return result_; + return result; } - public static boolean consumeTokenSmart(PsiBuilder builder_, IElementType token) { - addCompletionVariantSmart(builder_, token); - return consumeTokenFast(builder_, token); + public static boolean consumeTokenSmart(PsiBuilder builder, IElementType token) { + addCompletionVariantSmart(builder, token); + return consumeTokenFast(builder, token); } - public static boolean consumeTokenSmart(PsiBuilder builder_, String token) { - addCompletionVariantSmart(builder_, token); - return consumeTokenFast(builder_, token); + public static boolean consumeTokenSmart(PsiBuilder builder, String token) { + addCompletionVariantSmart(builder, token); + return consumeTokenFast(builder, token); } - public static boolean consumeToken(PsiBuilder builder_, IElementType token) { - addVariantSmart(builder_, token, true); - if (nextTokenIsFast(builder_, token)) { - builder_.advanceLexer(); + public static boolean consumeToken(PsiBuilder builder, IElementType token) { + addVariantSmart(builder, token, true); + if (nextTokenIsFast(builder, token)) { + builder.advanceLexer(); return true; } return false; } - public static boolean consumeTokenFast(PsiBuilder builder_, IElementType token) { - if (nextTokenIsFast(builder_, token)) { - builder_.advanceLexer(); + public static boolean consumeTokenFast(PsiBuilder builder, IElementType token) { + if (nextTokenIsFast(builder, token)) { + builder.advanceLexer(); return true; } return false; } - public static boolean consumeToken(PsiBuilder builder_, String text) { - return consumeToken(builder_, text, ErrorState.get(builder_).caseSensitive); + public static boolean consumeToken(PsiBuilder builder, String text) { + return consumeToken(builder, text, ErrorState.get(builder).caseSensitive); } - public static boolean consumeToken(PsiBuilder builder_, String text, boolean caseSensitive) { - addVariantSmart(builder_, text, true); - int count = nextTokenIsFast(builder_, text, caseSensitive); + public static boolean consumeToken(PsiBuilder builder, String text, boolean caseSensitive) { + addVariantSmart(builder, text, true); + int count = nextTokenIsFast(builder, text, caseSensitive); if (count > 0) { - while (count-- > 0) builder_.advanceLexer(); + while (count-- > 0) builder.advanceLexer(); return true; } return false; } - public static boolean consumeTokenFast(PsiBuilder builder_, String text) { - int count = nextTokenIsFast(builder_, text, ErrorState.get(builder_).caseSensitive); + public static boolean consumeTokenFast(PsiBuilder builder, String text) { + int count = nextTokenIsFast(builder, text, ErrorState.get(builder).caseSensitive); if (count > 0) { - while (count-- > 0) builder_.advanceLexer(); + while (count-- > 0) builder.advanceLexer(); return true; } return false; } - public static boolean nextTokenIsFast(PsiBuilder builder_, IElementType token) { - return builder_.getTokenType() == token; + public static boolean nextTokenIsFast(PsiBuilder builder, IElementType token) { + return builder.getTokenType() == token; } - public static boolean nextTokenIsFast(PsiBuilder builder_, IElementType... tokens) { - IElementType tokenType = builder_.getTokenType(); + public static boolean nextTokenIsFast(PsiBuilder builder, IElementType... tokens) { + IElementType tokenType = builder.getTokenType(); for (IElementType token : tokens) { if (token == tokenType) return true; } return false; } - public static boolean nextTokenIs(PsiBuilder builder_, String frameName, IElementType... tokens) { - ErrorState state = ErrorState.get(builder_); + public static boolean nextTokenIs(PsiBuilder builder, String frameName, IElementType... tokens) { + ErrorState state = ErrorState.get(builder); if (state.completionState != null) return true; boolean track = !state.suppressErrors && state.predicateCount < 2 && state.predicateSign; - if (!track) return nextTokenIsFast(builder_, tokens); - IElementType tokenType = builder_.getTokenType(); + if (!track) return nextTokenIsFast(builder, tokens); + IElementType tokenType = builder.getTokenType(); if (StringUtil.isNotEmpty(frameName)) { - addVariantInner(state, builder_.rawTokenIndex(), frameName); + addVariantInner(state, builder.rawTokenIndex(), frameName); } else { for (IElementType token : tokens) { - addVariant(builder_, state, token); + addVariant(builder, state, token); } } if (tokenType == null) return false; @@ -263,23 +263,23 @@ public class GeneratedParserUtilBase { return false; } - public static boolean nextTokenIs(PsiBuilder builder_, IElementType token) { - if (!addVariantSmart(builder_, token, false)) return true; - return nextTokenIsFast(builder_, token); + public static boolean nextTokenIs(PsiBuilder builder, IElementType token) { + if (!addVariantSmart(builder, token, false)) return true; + return nextTokenIsFast(builder, token); } - public static boolean nextTokenIs(PsiBuilder builder_, String tokenText) { - if (!addVariantSmart(builder_, tokenText, false)) return true; - return nextTokenIsFast(builder_, tokenText, ErrorState.get(builder_).caseSensitive) > 0; + public static boolean nextTokenIs(PsiBuilder builder, String tokenText) { + if (!addVariantSmart(builder, tokenText, false)) return true; + return nextTokenIsFast(builder, tokenText, ErrorState.get(builder).caseSensitive) > 0; } - public static boolean nextTokenIsFast(PsiBuilder builder_, String tokenText) { - return nextTokenIsFast(builder_, tokenText, ErrorState.get(builder_).caseSensitive) > 0; + public static boolean nextTokenIsFast(PsiBuilder builder, String tokenText) { + return nextTokenIsFast(builder, tokenText, ErrorState.get(builder).caseSensitive) > 0; } - public static int nextTokenIsFast(PsiBuilder builder_, String tokenText, boolean caseSensitive) { - CharSequence sequence = builder_.getOriginalText(); - int offset = builder_.getCurrentOffset(); + public static int nextTokenIsFast(PsiBuilder builder, String tokenText, boolean caseSensitive) { + CharSequence sequence = builder.getOriginalText(); + int offset = builder.getCurrentOffset(); int endOffset = offset + tokenText.length(); CharSequence subSequence = sequence.subSequence(offset, Math.min(endOffset, sequence.length())); @@ -287,7 +287,7 @@ public class GeneratedParserUtilBase { int count = 0; while (true) { - int nextOffset = builder_.rawTokenTypeStart(++count); + int nextOffset = builder.rawTokenTypeStart(++count); if (nextOffset > endOffset) { return -count; } @@ -298,36 +298,36 @@ public class GeneratedParserUtilBase { return count; } - private static void addCompletionVariantSmart(PsiBuilder builder_, Object token) { - ErrorState state = ErrorState.get(builder_); + private static void addCompletionVariantSmart(PsiBuilder builder, Object token) { + ErrorState state = ErrorState.get(builder); CompletionState completionState = state.completionState; if (completionState != null && state.predicateCount == 0) { - addCompletionVariant(builder_, completionState, token); + addCompletionVariant(builder, completionState, token); } } - private static boolean addVariantSmart(PsiBuilder builder_, Object token, boolean force) { - ErrorState state = ErrorState.get(builder_); + private static boolean addVariantSmart(PsiBuilder builder, Object token, boolean force) { + ErrorState state = ErrorState.get(builder); // skip FIRST check in completion mode if (state.completionState != null && !force) return false; - builder_.eof(); + builder.eof(); if (!state.suppressErrors && state.predicateCount < 2) { - addVariant(builder_, state, token); + addVariant(builder, state, token); } return true; } - public static void addVariant(PsiBuilder builder_, String text) { - addVariant(builder_, ErrorState.get(builder_), text); + public static void addVariant(PsiBuilder builder, String text) { + addVariant(builder, ErrorState.get(builder), text); } - private static void addVariant(PsiBuilder builder_, ErrorState state, Object o) { - builder_.eof(); // skip whitespaces - addVariantInner(state, builder_.rawTokenIndex(), o); + private static void addVariant(PsiBuilder builder, ErrorState state, Object o) { + builder.eof(); // skip whitespaces + addVariantInner(state, builder.rawTokenIndex(), o); CompletionState completionState = state.completionState; if (completionState != null && state.predicateSign) { - addCompletionVariant(builder_, completionState, o); + addCompletionVariant(builder, completionState, o); } } @@ -344,9 +344,9 @@ public class GeneratedParserUtilBase { } } - private static void addCompletionVariant(@NotNull PsiBuilder builder_, @NotNull CompletionState completionState, Object o) { - int offset = builder_.getCurrentOffset(); - if (!builder_.eof() && offset == builder_.rawTokenTypeStart(1)) return; // suppress for zero-length tokens + private static void addCompletionVariant(@NotNull PsiBuilder builder, @NotNull CompletionState completionState, Object o) { + int offset = builder.getCurrentOffset(); + if (!builder.eof() && offset == builder.rawTokenTypeStart(1)) return; // suppress for zero-length tokens boolean add = false; int diff = completionState.offset - offset; @@ -357,18 +357,18 @@ public class GeneratedParserUtilBase { add = true; } else if (diff > 0 && diff <= length) { - CharSequence fragment = builder_.getOriginalText().subSequence(offset, completionState.offset); + CharSequence fragment = builder.getOriginalText().subSequence(offset, completionState.offset); add = completionState.prefixMatches(fragment.toString(), text); } else if (diff < 0) { for (int i=-1; ; i--) { - IElementType type = builder_.rawLookup(i); - int tokenStart = builder_.rawTokenTypeStart(i); - if (isWhitespaceOrComment(builder_, type)) { + IElementType type = builder.rawLookup(i); + int tokenStart = builder.rawTokenTypeStart(i); + if (isWhitespaceOrComment(builder, type)) { diff = completionState.offset - tokenStart; } else if (type != null && tokenStart < completionState.offset) { - CharSequence fragment = builder_.getOriginalText().subSequence(tokenStart, completionState.offset); + CharSequence fragment = builder.getOriginalText().subSequence(tokenStart, completionState.offset); if (completionState.prefixMatches(fragment.toString(), text)) { diff = completionState.offset - tokenStart; } @@ -381,12 +381,12 @@ public class GeneratedParserUtilBase { add = add && length > 1 && !(text.charAt(0) == '<' && text.charAt(length - 1) == '>') && !(text.charAt(0) == '\'' && text.charAt(length - 1) == '\'' && length < 5); if (add) { - completionState.addItem(builder_, text); + completionState.addItem(builder, text); } } - public static boolean isWhitespaceOrComment(@NotNull PsiBuilder builder_, @Nullable IElementType type) { - return ((PsiBuilderImpl)((Builder)builder_).getDelegate()).whitespaceOrComment(type); + public static boolean isWhitespaceOrComment(@NotNull PsiBuilder builder, @Nullable IElementType type) { + return ((PsiBuilderImpl)((Builder)builder).getDelegate()).whitespaceOrComment(type); } // here's the new section API for compact parsers & less IntelliJ platform API exposure @@ -398,35 +398,35 @@ public class GeneratedParserUtilBase { public static final int _NOT_ = 0x10; // simple enter/exit methods pair that doesn't require frame object - public static PsiBuilder.Marker enter_section_(PsiBuilder builder_) { - return builder_.mark(); + public static PsiBuilder.Marker enter_section_(PsiBuilder builder) { + return builder.mark(); } - public static void exit_section_(PsiBuilder builder_, + public static void exit_section_(PsiBuilder builder, PsiBuilder.Marker marker, @Nullable IElementType elementType, boolean result) { - close_marker_impl_(ErrorState.get(builder_).frameStack.peekLast(), marker, elementType, result); + close_marker_impl_(ErrorState.get(builder).frameStack.peekLast(), marker, elementType, result); } // complex enter/exit methods pair with frame object - public static PsiBuilder.Marker enter_section_(PsiBuilder builder_, int level, int modifiers, @Nullable String frameName) { - PsiBuilder.Marker marker = builder_.mark(); - enter_section_impl_(builder_, level, modifiers, frameName); + public static PsiBuilder.Marker enter_section_(PsiBuilder builder, int level, int modifiers, @Nullable String frameName) { + PsiBuilder.Marker marker = builder.mark(); + enter_section_impl_(builder, level, modifiers, frameName); return marker; } - private static void enter_section_impl_(PsiBuilder builder_, int level, int modifiers, @Nullable String frameName) { - ErrorState state = ErrorState.get(builder_); - Frame frame = state.FRAMES.alloc().init(builder_, state, level, modifiers, frameName); + private static void enter_section_impl_(PsiBuilder builder, int level, int modifiers, @Nullable String frameName) { + ErrorState state = ErrorState.get(builder); + Frame frame = state.FRAMES.alloc().init(builder, state, level, modifiers, frameName); Frame prevFrame = state.frameStack.peekLast(); if (prevFrame != null && prevFrame.errorReportedAt > frame.position) { // report error for previous unsuccessful frame - reportError(builder_, state, frame, true, false); + reportError(builder, state, frame, null, true, false); } if (((frame.modifiers & _LEFT_) | (frame.modifiers & _LEFT_INNER_)) != 0) { - PsiBuilder.Marker left = (PsiBuilder.Marker)builder_.getLatestDoneMarker(); - if (invalid_left_marker_guard_(builder_, left, frameName)) { + PsiBuilder.Marker left = (PsiBuilder.Marker)builder.getLatestDoneMarker(); + if (invalid_left_marker_guard_(builder, left, frameName)) { frame.leftMarker = left; } } @@ -448,14 +448,14 @@ public class GeneratedParserUtilBase { } } - public static void exit_section_(PsiBuilder builder_, + public static void exit_section_(PsiBuilder builder, int level, PsiBuilder.Marker marker, @Nullable IElementType elementType, boolean result, boolean pinned, @Nullable Parser eatMore) { - ErrorState state = ErrorState.get(builder_); + ErrorState state = ErrorState.get(builder); Frame frame = state.frameStack.pollLast(); if (frame == null || level != frame.level) { @@ -472,9 +472,19 @@ public class GeneratedParserUtilBase { state.FRAMES.recycle(frame); return; } - exit_section_impl_(state, frame, builder_, marker, elementType, result, pinned); + close_frame_impl_(state, frame, builder, marker, elementType, result, pinned); + exit_section_impl_(state, frame, builder, elementType, result, pinned, eatMore); + state.FRAMES.recycle(frame); + } - int initialPos = builder_.rawTokenIndex(); + private static void exit_section_impl_(ErrorState state, + Frame frame, + PsiBuilder builder, + @Nullable IElementType elementType, + boolean result, + boolean pinned, + @Nullable Parser eatMore) { + int initialPos = builder.rawTokenIndex(); boolean willFail = !result && !pinned; if (willFail && initialPos == frame.position && state.lastExpectedVariantPos == frame.position && frame.name != null && state.variants.size() - frame.variantCount > 1) { @@ -484,16 +494,16 @@ public class GeneratedParserUtilBase { int lastErrorPos = getLastVariantPos(state, initialPos); if (!state.suppressErrors && eatMore != null) { state.suppressErrors = true; - final boolean eatMoreFlagOnce = !builder_.eof() && eatMore.parse(builder_, frame.level + 1); + final boolean eatMoreFlagOnce = !builder.eof() && eatMore.parse(builder, frame.level + 1); boolean eatMoreFlag = eatMoreFlagOnce || !result && frame.position == initialPos && lastErrorPos > frame.position; PsiBuilderImpl.ProductionMarker latestDoneMarker = (pinned || result) && (state.altMode || elementType != null) && - eatMoreFlagOnce ? (PsiBuilderImpl.ProductionMarker)builder_.getLatestDoneMarker() : null; + eatMoreFlagOnce ? (PsiBuilderImpl.ProductionMarker)builder.getLatestDoneMarker() : null; PsiBuilder.Marker extensionMarker = null; IElementType extensionTokenType = null; // whitespace prefix makes the very first frame offset bigger than marker start offset which is always 0 - if (latestDoneMarker instanceof PsiBuilder.Marker && + if (latestDoneMarker != null && frame.position >= latestDoneMarker.getStartIndex() && frame.position <= latestDoneMarker.getEndIndex()) { extensionMarker = ((PsiBuilder.Marker)latestDoneMarker).precede(); @@ -503,27 +513,27 @@ public class GeneratedParserUtilBase { // advance to the last error pos // skip tokens until lastErrorPos. parseAsTree might look better here... int parenCount = 0; - while ((eatMoreFlag || parenCount > 0) && builder_.rawTokenIndex() < lastErrorPos) { + while ((eatMoreFlag || parenCount > 0) && builder.rawTokenIndex() < lastErrorPos) { if (state.braces != null) { - if (builder_.getTokenType() == state.braces[0].getLeftBraceType()) parenCount ++; - else if (builder_.getTokenType() == state.braces[0].getRightBraceType()) parenCount --; + if (builder.getTokenType() == state.braces[0].getLeftBraceType()) parenCount ++; + else if (builder.getTokenType() == state.braces[0].getRightBraceType()) parenCount --; } - builder_.advanceLexer(); - eatMoreFlag = eatMore.parse(builder_, frame.level + 1); + builder.advanceLexer(); + eatMoreFlag = eatMore.parse(builder, frame.level + 1); } boolean errorReported = frame.errorReportedAt == initialPos || !result && frame.errorReportedAt >= frame.position; if (errorReported) { if (eatMoreFlag) { - builder_.advanceLexer(); - parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); + builder.advanceLexer(); + parseAsTree(state, builder, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); } } else if (eatMoreFlag) { - errorReported = reportError(builder_, state, frame, true, true); - parseAsTree(state, builder_, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); + errorReported = reportError(builder, state, frame, null, true, true); + parseAsTree(state, builder, frame.level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER, eatMore); } - else if (eatMoreFlagOnce || (!result && frame.position != builder_.rawTokenIndex()) || frame.errorReportedAt > initialPos) { - errorReported = reportError(builder_, state, frame, true, false); + else if (eatMoreFlagOnce || (!result && frame.position != builder.rawTokenIndex()) || frame.errorReportedAt > initialPos) { + errorReported = reportError(builder, state, frame, null, true, false); } if (extensionMarker != null) { extensionMarker.done(extensionTokenType); @@ -539,7 +549,7 @@ public class GeneratedParserUtilBase { // do not report if there are errors beyond current position if (lastErrorPos == initialPos) { // do not force, inner recoverRoot might have skipped some tokens - reportError(builder_, state, frame, false, false); + reportError(builder, state, frame, elementType, false, false); } else if (lastErrorPos > initialPos) { // set error pos here as if it is reported for future reference @@ -551,19 +561,18 @@ public class GeneratedParserUtilBase { if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) { prevFrame.errorReportedAt = frame.errorReportedAt; } - state.FRAMES.recycle(frame); } - private static void exit_section_impl_(ErrorState state, - Frame frame, - PsiBuilder builder_, - PsiBuilder.Marker marker, - IElementType elementType, - boolean result, - boolean pinned) { + private static void close_frame_impl_(ErrorState state, + Frame frame, + PsiBuilder builder, + PsiBuilder.Marker marker, + IElementType elementType, + boolean result, + boolean pinned) { if (elementType != null && marker != null) { if ((frame.modifiers & _COLLAPSE_) != 0) { - PsiBuilderImpl.ProductionMarker last = result || pinned? (PsiBuilderImpl.ProductionMarker)builder_.getLatestDoneMarker() : null; + PsiBuilderImpl.ProductionMarker last = result || pinned? (PsiBuilderImpl.ProductionMarker)builder.getLatestDoneMarker() : null; if (last != null && last.getStartIndex() == frame.position && state.typeExtends(last.getTokenType(), elementType)) { IElementType resultType = last.getTokenType(); @@ -583,7 +592,7 @@ public class GeneratedParserUtilBase { frame.leftMarker.precede().done(elementType); } else { - if (frame.level == 0) builder_.eof(); // skip whitespaces + if (frame.level == 0) builder.eof(); // skip whitespaces marker.done(elementType); } } @@ -624,20 +633,20 @@ public class GeneratedParserUtilBase { } } - public static boolean report_error_(PsiBuilder builder_, boolean result_) { - if (!result_) report_error_(builder_, ErrorState.get(builder_), false); - return result_; + public static boolean report_error_(PsiBuilder builder, boolean result) { + if (!result) report_error_(builder, ErrorState.get(builder), false); + return result; } - public static void report_error_(PsiBuilder builder_, ErrorState state, boolean advance) { + public static void report_error_(PsiBuilder builder, ErrorState state, boolean advance) { Frame frame = state.frameStack.isEmpty()? null : state.frameStack.getLast(); if (frame == null) { LOG.error("unbalanced enter/exit section call: got null"); return; } - int position = builder_.rawTokenIndex(); + int position = builder.rawTokenIndex(); if (frame.errorReportedAt < position && getLastVariantPos(state, position + 1) <= position) { - reportError(builder_, state, frame, true, advance); + reportError(builder, state, frame, null, true, advance); } } @@ -645,28 +654,43 @@ public class GeneratedParserUtilBase { return state.lastExpectedVariantPos < 0? defValue : state.lastExpectedVariantPos; } - private static boolean reportError(PsiBuilder builder_, + private static boolean reportError(PsiBuilder builder, ErrorState state, Frame frame, + IElementType elementType, boolean force, boolean advance) { - String expectedText = state.getExpectedText(builder_); + String expectedText = state.getExpectedText(builder); boolean notEmpty = StringUtil.isNotEmpty(expectedText); if (force || notEmpty || advance) { - String gotText = builder_.eof()? "unexpected end of file" : - notEmpty? "got '" + builder_.getTokenText() +"'" : - "'" + builder_.getTokenText() +"' unexpected"; + String gotText = builder.eof()? "unexpected end of file" : + notEmpty? "got '" + builder.getTokenText() +"'" : + "'" + builder.getTokenText() +"' unexpected"; String message = expectedText + gotText; if (advance) { - PsiBuilder.Marker mark = builder_.mark(); - builder_.advanceLexer(); + PsiBuilder.Marker mark = builder.mark(); + builder.advanceLexer(); mark.error(message); } - else { - builder_.error(message); + else if (!force) { + PsiBuilder.Marker extensionMarker = null; + IElementType extensionTokenType = null; + PsiBuilderImpl.ProductionMarker latestDoneMarker = elementType == null ? null : (PsiBuilderImpl.ProductionMarker)builder.getLatestDoneMarker(); + if (latestDoneMarker != null && + frame.position >= latestDoneMarker.getStartIndex() && + frame.position <= latestDoneMarker.getEndIndex()) { + extensionMarker = ((PsiBuilder.Marker)latestDoneMarker).precede(); + extensionTokenType = latestDoneMarker.getTokenType(); + ((PsiBuilder.Marker)latestDoneMarker).drop(); + } + builder.error(message); + if (extensionMarker != null) extensionMarker.done(extensionTokenType); } - builder_.eof(); // skip whitespaces - frame.errorReportedAt = builder_.rawTokenIndex(); + else { + builder.error(message); + } + builder.eof(); // skip whitespaces + frame.errorReportedAt = builder.rawTokenIndex(); return true; } return false; @@ -710,8 +734,8 @@ public class GeneratedParserUtilBase { public final ErrorState state; public final PsiParser parser; - public Builder(PsiBuilder builder_, ErrorState state_, PsiParser parser_) { - super(builder_); + public Builder(PsiBuilder builder, ErrorState state_, PsiParser parser_) { + super(builder); state = state_; parser = parser_; } @@ -785,13 +809,12 @@ public class GeneratedParserUtilBase { if (state.braces != null && state.braces.length == 0) state.braces = null; } - public String getExpectedText(PsiBuilder builder_) { - int position = builder_.rawTokenIndex(); + public String getExpectedText(PsiBuilder builder) { + int position = builder.rawTokenIndex(); StringBuilder sb = new StringBuilder(); if (addExpected(sb, position, true)) { sb.append(" expected, "); } - else if (addExpected(sb, position, false)) sb.append(" unexpected, "); return sb.toString(); } @@ -846,14 +869,14 @@ public class GeneratedParserUtilBase { list.setSize(start); } - boolean typeExtends(IElementType child_, IElementType parent_) { - if (child_ == parent_) return true; + boolean typeExtends(IElementType child, IElementType parent) { + if (child == parent) return true; if (extendsSets != null) { for (TokenSet set : extendsSets) { - if (set.contains(child_) && set.contains(parent_)) return true; + if (set.contains(child) && set.contains(parent)) return true; } } - return altExtendsChecker != null && altExtendsChecker.process(child_, parent_); + return altExtendsChecker != null && altExtendsChecker.process(child, parent); } } @@ -871,9 +894,9 @@ public class GeneratedParserUtilBase { public Frame() { } - public Frame init(PsiBuilder builder_, ErrorState state, int level_, int modifiers_, String name_) { - offset = builder_.getCurrentOffset(); - position = builder_.rawTokenIndex(); + public Frame init(PsiBuilder builder, ErrorState state, int level_, int modifiers_, String name_) { + offset = builder.getCurrentOffset(); + position = builder.rawTokenIndex(); level = level_; modifiers = modifiers_; name = name_; @@ -937,7 +960,7 @@ public class GeneratedParserUtilBase { private static final int MAX_CHILDREN_IN_TREE = 10; - public static boolean parseAsTree(ErrorState state, final PsiBuilder builder_, int level, final IElementType chunkType, + public static boolean parseAsTree(ErrorState state, final PsiBuilder builder, int level, final IElementType chunkType, boolean checkBraces, final Parser parser, final Parser eatMoreCondition) { final LinkedList> parenList = new LinkedList>(); final LinkedList> siblingList = new LinkedList>(); @@ -973,14 +996,14 @@ public class GeneratedParserUtilBase { int tokenCount = 0; if (checkParens) { int tokenIdx = -1; - while (builder_.rawLookup(tokenIdx) == TokenType.WHITE_SPACE) tokenIdx --; - LighterASTNode doneMarker = builder_.rawLookup(tokenIdx) == state.braces[0].getLeftBraceType() ? builder_.getLatestDoneMarker() : null; - if (doneMarker != null && doneMarker.getStartOffset() == builder_.rawTokenTypeStart(tokenIdx) && doneMarker.getTokenType() == TokenType.ERROR_ELEMENT) { + while (builder.rawLookup(tokenIdx) == TokenType.WHITE_SPACE) tokenIdx --; + LighterASTNode doneMarker = builder.rawLookup(tokenIdx) == state.braces[0].getLeftBraceType() ? builder.getLatestDoneMarker() : null; + if (doneMarker != null && doneMarker.getStartOffset() == builder.rawTokenTypeStart(tokenIdx) && doneMarker.getTokenType() == TokenType.ERROR_ELEMENT) { parenList.add(Pair.create(((PsiBuilder.Marker)doneMarker).precede(), (PsiBuilder.Marker)null)); } } while (true) { - final IElementType tokenType = builder_.getTokenType(); + final IElementType tokenType = builder.getTokenType(); if (checkParens && (tokenType == state.braces[0].getLeftBraceType() || tokenType == state.braces[0].getRightBraceType() && !parenList.isEmpty())) { if (marker != null) { marker.done(chunkType); @@ -990,10 +1013,10 @@ public class GeneratedParserUtilBase { } if (tokenType == state.braces[0].getLeftBraceType()) { final Pair prev = siblingList.peek(); - parenList.addFirst(Pair.create(builder_.mark(), prev == null ? null : prev.first)); + parenList.addFirst(Pair.create(builder.mark(), prev == null ? null : prev.first)); } checkSiblingsRunnable.run(); - builder_.advanceLexer(); + builder.advanceLexer(); if (tokenType == state.braces[0].getRightBraceType()) { final Pair pair = parenList.removeFirst(); pair.first.done(chunkType); @@ -1007,10 +1030,10 @@ public class GeneratedParserUtilBase { } else { if (marker == null) { - marker = builder_.mark(); + marker = builder.mark(); marker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, null); } - final boolean result = (!parenList.isEmpty() || eatMoreCondition.parse(builder_, level + 1)) && parser.parse(builder_, level + 1); + final boolean result = (!parenList.isEmpty() || eatMoreCondition.parse(builder, level + 1)) && parser.parse(builder, level + 1); if (result) { tokenCount++; totalCount++; @@ -1037,7 +1060,7 @@ public class GeneratedParserUtilBase { return totalCount != 0; } - private static class DummyBlockElementType extends IElementType implements ICompositeElementType{ + private static class DummyBlockElementType extends IElementType implements ICompositeElementType { DummyBlockElementType() { super("DUMMY_BLOCK", Language.ANY); } From beb05962073b43452b322dd235d81398d967832d Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 30 Sep 2014 04:40:13 +0200 Subject: [PATCH 45/78] Fixed reading from proc file. --- .../python/internal/ProcessUtils.java | 39 ++++++++++++++++++- .../internal/linux/ProcessListLinux.java | 3 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/internal/ProcessUtils.java b/python/pydevSrc/com/jetbrains/python/internal/ProcessUtils.java index 99922fe96732..80565ac31d82 100644 --- a/python/pydevSrc/com/jetbrains/python/internal/ProcessUtils.java +++ b/python/pydevSrc/com/jetbrains/python/internal/ProcessUtils.java @@ -13,12 +13,14 @@ package com.jetbrains.python.internal; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; +import com.jetbrains.python.console.pydev.FastStringBuffer; import com.jetbrains.python.internal.linux.ProcessListLinux; import com.jetbrains.python.internal.macos.ProcessListMac; import com.jetbrains.python.internal.win32.ProcessListWin32; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; public class ProcessUtils { @@ -68,4 +70,37 @@ public class ProcessUtils { } }; } + + @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; + + FastStringBuffer buffer = new FastStringBuffer(DEFAULT_FILE_SIZE); + + while (n > 0) { + buffer.append(readBuffer, 0, n); + n = reader.read(readBuffer); + } + + return buffer.toCharArray(); + } } diff --git a/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java b/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java index edada5cf09aa..fa704a06c93c 100644 --- a/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java +++ b/python/pydevSrc/com/jetbrains/python/internal/linux/ProcessListLinux.java @@ -15,6 +15,7 @@ import java.io.FilenameFilter; import java.io.IOException; import com.intellij.openapi.util.io.FileUtil; +import com.jetbrains.python.internal.ProcessUtils; import com.jetbrains.python.internal.PyProcessInfo; import com.jetbrains.python.internal.IProcessList; import com.jetbrains.python.internal.PyProcessInfo; @@ -64,7 +65,7 @@ public class ProcessListLinux implements IProcessList { File cmdLine = new File(pidFiles[i], "cmdline"); //$NON-NLS-1$ String name; try { - name = FileUtil.loadFile(cmdLine).replace('\0', ' '); + name = new String(ProcessUtils.loadFileText(cmdLine, null)).replace('\0', ' '); } catch (IOException e) { name = ""; From 0f996f5e533d70609c1eff7de069dd3fed4d53f3 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 26 Sep 2014 11:34:37 +0400 Subject: [PATCH 46/78] classpath panel: cleanup --- .../roots/ui/configuration/classpath/ClasspathPanelImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index 25108a7c5c1a..7b71c7547ee8 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -289,7 +289,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { rootConfigurable.select((LibraryOrderEntry)entry, true); } else { - myEditButton.actionPerformed(null); + doEdit(); } } else if (entry instanceof JdkOrderEntry) { From d7970314ab309572420fe9345a7349435e1d398b Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 26 Sep 2014 17:24:15 +0400 Subject: [PATCH 47/78] classpath panel: change order entries immediately and get rid of flushing changes to model (EA-31955) --- .../ui/configuration/ClasspathEditor.java | 15 +-------------- .../classpath/ClasspathPanelImpl.java | 18 ++++++++---------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathEditor.java index 89cc49eb820a..42effb123dd6 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ClasspathEditor.java @@ -29,7 +29,6 @@ import com.intellij.openapi.roots.impl.storage.ClasspathStorage; import com.intellij.openapi.roots.impl.storage.ClasspathStorageProvider; import com.intellij.openapi.roots.ui.configuration.classpath.ClasspathPanelImpl; import com.intellij.openapi.util.Disposer; -import com.intellij.ui.OrderPanelListener; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -77,7 +76,6 @@ public class ClasspathEditor extends ModuleElementsEditor implements ModuleRootL @Override public void saveData() { myPanel.stopEditing(); - flushChangesToModel(); } @Override @@ -99,14 +97,6 @@ public class ClasspathEditor extends ModuleElementsEditor implements ModuleRootL @Override public JComponent createComponentImpl() { myPanel = new ClasspathPanelImpl(getState()); - - myPanel.addListener(new OrderPanelListener() { - @Override - public void entryMoved() { - flushChangesToModel(); - } - }); - final JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); panel.add(myPanel, BorderLayout.CENTER); @@ -131,9 +121,8 @@ public class ClasspathEditor extends ModuleElementsEditor implements ModuleRootL return panel; } + @Deprecated public void flushChangesToModel() { - List entries = myPanel.getEntries(); - getModel().rearrangeOrderEntries(entries.toArray(new OrderEntry[entries.size()])); } public void selectOrderEntry(@NotNull final OrderEntry entry) { @@ -170,8 +159,6 @@ public class ClasspathEditor extends ModuleElementsEditor implements ModuleRootL if (myPanel != null) { myPanel.forceInitFromModel(); } - - flushChangesToModel(); } private class ClasspathFormatPanel extends JPanel { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index 7b71c7547ee8..ef0dc0e89a92 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -575,28 +575,26 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { } private void moveSelectedRows(int increment) { - if (increment == 0) { - return; - } - if (myEntryTable.isEditing()){ + LOG.assertTrue(increment == -1 || increment == 1); + if (myEntryTable.isEditing()) { myEntryTable.getCellEditor().stopCellEditing(); } final ListSelectionModel selectionModel = myEntryTable.getSelectionModel(); - for(int row = increment < 0? 0 : myModel.getRowCount() - 1; increment < 0? row < myModel.getRowCount() : row >= 0; row += - increment < 0? +1 : -1){ + for (int row = increment < 0 ? 0 : myModel.getRowCount() - 1; increment < 0 ? row < myModel.getRowCount() : row >= 0; row += + increment < 0 ? +1 : -1) { if (selectionModel.isSelectedIndex(row)) { final int newRow = moveRow(row, increment); selectionModel.removeSelectionInterval(row, row); selectionModel.addSelectionInterval(newRow, newRow); } } + List entries = getEntries(); + myState.getRootModel().rearrangeOrderEntries(entries.toArray(new OrderEntry[entries.size()])); + myModel.fireTableRowsUpdated(0, myModel.getRowCount() - 1); Rectangle cellRect = myEntryTable.getCellRect(selectionModel.getMinSelectionIndex(), 0, true); - if (cellRect != null) { - myEntryTable.scrollRectToVisible(cellRect); - } + myEntryTable.scrollRectToVisible(cellRect); myEntryTable.repaint(); - myListeners.getMulticaster().entryMoved(); } public void selectOrderEntry(@NotNull OrderEntry entry) { From 25fcc90285645f328489e1e08e5a5cba10ba6175 Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 29 Sep 2014 20:45:57 +0400 Subject: [PATCH 48/78] TableUtil: fixed 'removeSelectedItems' when items are sorted --- platform/util/src/com/intellij/ui/TableUtil.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/util/src/com/intellij/ui/TableUtil.java b/platform/util/src/com/intellij/ui/TableUtil.java index 28aa8d96e24c..25aae882205f 100644 --- a/platform/util/src/com/intellij/ui/TableUtil.java +++ b/platform/util/src/com/intellij/ui/TableUtil.java @@ -114,8 +114,9 @@ public class TableUtil { TableModel model = table.getModel(); boolean removed = false; for (int index = maxSelectionIndex; index >= 0; index--) { - if (selectionModel.isSelectedIndex(index) && (applyable == null || applyable.isOperationApplyable(model, index))) { - itemRemovable.removeRow(index); + int modelIndex = table.convertRowIndexToModel(index); + if (selectionModel.isSelectedIndex(index) && (applyable == null || applyable.isOperationApplyable(model, modelIndex))) { + itemRemovable.removeRow(modelIndex); removed = true; } } From c54dcaf02fee22e244eb99e61418ae665b4f1af7 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 30 Sep 2014 10:53:32 +0400 Subject: [PATCH 49/78] IDEA-77778: Add ability to view Module Dependencies in sorted order --- .../classpath/ClasspathPanelImpl.java | 117 +++++++--- .../classpath/ClasspathTableItem.java | 14 ++ .../classpath/ClasspathTableModel.java | 199 ++++++++++-------- 3 files changed, 214 insertions(+), 116 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index ef0dc0e89a92..9a65ba9f80cf 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -63,7 +63,9 @@ import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.table.JBTable; import com.intellij.util.EventDispatcher; import com.intellij.util.IconUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.TextTransferable; +import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -73,15 +75,16 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; import java.awt.*; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.util.ArrayList; +import java.util.*; import java.util.List; -import java.util.Set; public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.classpath.ClasspathPanelImpl"); @@ -98,7 +101,27 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { myState = state; myModel = new ClasspathTableModel(state, getStructureConfigurableContext()); - myEntryTable = new JBTable(myModel); + myEntryTable = new JBTable(myModel) { + @Override + protected TableRowSorter createRowSorter(TableModel model) { + return new DefaultColumnInfoBasedRowSorter(model) { + @Override + public void toggleSortOrder(int column) { + if (isSortable(column)) { + SortKey oldKey = ContainerUtil.getFirstItem(getSortKeys()); + SortOrder oldOrder; + if (oldKey == null || oldKey.getColumn() != column) { + oldOrder = SortOrder.UNSORTED; + } + else { + oldOrder = oldKey.getSortOrder(); + } + setSortKeys(Collections.singletonList(new SortKey(column, getNextSortOrder(oldOrder)))); + } + } + }; + } + }; myEntryTable.setShowGrid(false); myEntryTable.setDragEnabled(false); myEntryTable.setIntercellSpacing(new Dimension(0, 0)); @@ -149,7 +172,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { final int count = myModel.getRowCount(); Object[] elements = new Object[count]; for (int idx = 0; idx < count; idx++) { - elements[idx] = myModel.getItemAt(idx); + elements[idx] = myModel.getItem(idx); } return elements; } @@ -163,7 +186,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { public void selectElement(Object element, String selectedText) { final int count = myModel.getRowCount(); for (int row = 0; row < count; row++) { - if (element.equals(myModel.getItemAt(row))) { + if (element.equals(myModel.getItem(row))) { final int viewRow = myEntryTable.convertRowIndexToView(row); myEntryTable.getSelectionModel().setSelectionInterval(viewRow, viewRow); TableUtil.scrollSelectionToVisible(myEntryTable); @@ -172,8 +195,8 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { } } }; - setFixedColumnWidth(ClasspathTableModel.EXPORT_COLUMN, ClasspathTableModel.EXPORT_COLUMN_NAME); - setFixedColumnWidth(ClasspathTableModel.SCOPE_COLUMN, DependencyScope.COMPILE.toString() + " "); // leave space for combobox border + setFixedColumnWidth(ClasspathTableModel.EXPORT_COLUMN); + setFixedColumnWidth(ClasspathTableModel.SCOPE_COLUMN); // leave space for combobox border myEntryTable.registerKeyboardAction( new ActionListener() { @@ -182,14 +205,14 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { final int[] selectedRows = myEntryTable.getSelectedRows(); boolean currentlyMarked = true; for (final int selectedRow : selectedRows) { - final ClasspathTableItem item = myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow)); + final ClasspathTableItem item = getItemAt(selectedRow); if (selectedRow < 0 || !item.isExportable()) { return; } currentlyMarked &= item.isExported(); } for (final int selectedRow : selectedRows) { - myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow)).setExported(!currentlyMarked); + getItemAt(selectedRow).setExported(!currentlyMarked); } myModel.fireTableDataChanged(); TableUtil.selectRows(myEntryTable, selectedRows); @@ -256,6 +279,23 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { PopupHandler.installPopupHandler(myEntryTable, actionGroup, ActionPlaces.UNKNOWN, ActionManager.getInstance()); } + @NotNull + private static SortOrder getNextSortOrder(@NotNull SortOrder order) { + switch (order) { + case ASCENDING: + return SortOrder.DESCENDING; + case DESCENDING: + return SortOrder.UNSORTED; + case UNSORTED: + default: + return SortOrder.ASCENDING; + } + } + + private ClasspathTableItem getItemAt(int selectedRow) { + return myModel.getItem(myEntryTable.convertRowIndexToModel(selectedRow)); + } + private void addChangeLibraryLevelAction(DefaultActionGroup actionGroup, String tableLevel) { final LibraryTablePresentation presentation = LibraryEditingUtil.getLibraryTablePresentation(getProject(), tableLevel); actionGroup.add(new ChangeLibraryLevelInClasspathAction(this, presentation.getDisplayName(true), tableLevel)); @@ -265,10 +305,10 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { @Nullable public OrderEntry getSelectedEntry() { if (myEntryTable.getSelectedRowCount() != 1) return null; - return myModel.getItemAt(myEntryTable.getSelectedRow()).getEntry(); + return getItemAt(myEntryTable.getSelectedRow()).getEntry(); } - private void setFixedColumnWidth(final int columnIndex, final String textToMeasure) { + private void setFixedColumnWidth(final int columnIndex) { final TableColumn column = myEntryTable.getTableHeader().getColumnModel().getColumn(columnIndex); column.setResizable(false); column.setMaxWidth(column.getPreferredWidth()); @@ -335,6 +375,17 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { }); final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myEntryTable); + AnActionButtonUpdater moveUpDownUpdater = new AnActionButtonUpdater() { + @Override + public boolean isEnabled(AnActionEvent e) { + for (RowSorter.SortKey key : myEntryTable.getRowSorter().getSortKeys()) { + if (key.getSortOrder() != SortOrder.UNSORTED) { + return false; + } + } + return true; + } + }; decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { @@ -390,12 +441,16 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { moveSelectedRows(-1); } }) + .setMoveUpActionUpdater(moveUpDownUpdater) + .setMoveUpActionName("Move Up (disabled if items are shown in sorted order)") .setMoveDownAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { moveSelectedRows(+1); } }) + .setMoveDownActionUpdater(moveUpDownUpdater) + .setMoveDownActionName("Move Down (disabled if items are shown in sorted order)") .addExtraAction(myEditButton); if (isAnalyzeShown) { decorator.addExtraAction(analyzeButton); @@ -440,7 +495,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { for (final int selectedRow : selectedRows) { minRow = Math.min(minRow, selectedRow); maxRow = Math.max(maxRow, selectedRow); - final ClasspathTableItem item = myModel.getItemAt(selectedRow); + final ClasspathTableItem item = getItemAt(selectedRow); if (!item.isRemovable()) { removeButtonEnabled = false; } @@ -448,7 +503,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { if (myRemoveButton != null) { myRemoveButton.setEnabled(removeButtonEnabled && selectedRows.length > 0); } - ClasspathTableItem selectedItem = selectedRows.length == 1 ? myModel.getItemAt(selectedRows[0]) : null; + ClasspathTableItem selectedItem = selectedRows.length == 1 ? getItemAt(selectedRows[0]) : null; myEditButton.setEnabled(selectedItem != null && selectedItem.isEditable()); } @@ -504,11 +559,13 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { @Override public void addItems(List> toAdd) { for (ClasspathTableItem item : toAdd) { - myModel.addItem(item); + myModel.addRow(item); } - myModel.fireTableDataChanged(); - final ListSelectionModel selectionModel = myEntryTable.getSelectionModel(); - selectionModel.setSelectionInterval(myModel.getRowCount() - toAdd.size(), myModel.getRowCount() - 1); + TIntArrayList toSelect = new TIntArrayList(); + for (int i = myModel.getRowCount() - toAdd.size(); i < myModel.getRowCount(); i++) { + toSelect.add(myEntryTable.convertRowIndexToView(i)); + } + TableUtil.selectRows(myEntryTable, toSelect.toNativeArray()); TableUtil.scrollSelectionToVisible(myEntryTable); final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myState.getProject()).getContext(); @@ -599,7 +656,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { public void selectOrderEntry(@NotNull OrderEntry entry) { for (int row = 0; row < myModel.getRowCount(); row++) { - final OrderEntry orderEntry = myModel.getItemAt(row).getEntry(); + final OrderEntry orderEntry = getItemAt(row).getEntry(); if (orderEntry != null && entry.getPresentableName().equals(orderEntry.getPresentableName())) { myEntryTable.getSelectionModel().setSelectionInterval(row, row); TableUtil.scrollSelectionToVisible(myEntryTable); @@ -610,8 +667,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { private int moveRow(final int row, final int increment) { int newIndex = Math.abs(row + increment) % myModel.getRowCount(); - final ClasspathTableItem item = myModel.removeDataRow(row); - myModel.addItemAt(item, newIndex); + myModel.exchangeRows(row, newIndex); return newIndex; } @@ -623,7 +679,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { final int count = myModel.getRowCount(); final List entries = new ArrayList(count); for (int row = 0; row < count; row++) { - final OrderEntry entry = myModel.getItemAt(row).getEntry(); + final OrderEntry entry = myModel.getItem(row).getEntry(); if (entry != null) { entries.add(entry); } @@ -639,16 +695,25 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { } public void forceInitFromModel() { - final int[] selection = myEntryTable.getSelectedRows(); + Set> oldSelection = new HashSet>(); + for (int i : myEntryTable.getSelectedRows()) { + ContainerUtil.addIfNotNull(getItemAt(i), oldSelection); + } myModel.clear(); myModel.init(); myModel.fireTableDataChanged(); - TableUtil.selectRows(myEntryTable, selection); + TIntArrayList newSelection = new TIntArrayList(); + for (int i = 0; i < myModel.getRowCount(); i++) { + if (oldSelection.contains(getItemAt(i))) { + newSelection.add(i); + } + } + TableUtil.selectRows(myEntryTable, newSelection.toNativeArray()); } - private static CellAppearanceEx getCellAppearance(final ClasspathTableItem item, - final StructureConfigurableContext context, - final boolean selected) { + static CellAppearanceEx getCellAppearance(final ClasspathTableItem item, + final StructureConfigurableContext context, + final boolean selected) { final OrderEntryAppearanceService service = OrderEntryAppearanceService.getInstance(); if (item instanceof InvalidJdkItem) { return service.forJdk(null, false, selected, true); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableItem.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableItem.java index f11e2295eaec..10bd32a9d1c0 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableItem.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableItem.java @@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration.classpath; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.util.Comparing; import org.jetbrains.annotations.Nullable; /** @@ -95,4 +96,17 @@ class ClasspathTableItem { return null; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ClasspathTableItem item = (ClasspathTableItem)o; + return Comparing.equal(myEntry, item.myEntry); + } + + @Override + public int hashCode() { + return myEntry != null ? myEntry.hashCode() : 0; + } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableModel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableModel.java index 8ffb161f488e..0be7e2def702 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableModel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathTableModel.java @@ -15,7 +15,6 @@ */ package com.intellij.openapi.roots.ui.configuration.classpath; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.roots.JdkOrderEntry; @@ -23,32 +22,105 @@ import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState; import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.util.Comparing; +import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ItemRemovable; +import com.intellij.util.ui.ListTableModel; +import org.jetbrains.annotations.Nullable; -import javax.swing.table.AbstractTableModel; +import javax.swing.*; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; /** * @author nik */ -class ClasspathTableModel extends AbstractTableModel implements ItemRemovable { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.classpath.ClasspathTableModel"); - public static final String EXPORT_COLUMN_NAME = ProjectBundle.message("modules.order.export.export.column"); +class ClasspathTableModel extends ListTableModel> implements ItemRemovable { + private static final String EXPORT_COLUMN_NAME = ProjectBundle.message("modules.order.export.export.column"); + private static final ColumnInfo, Boolean> EXPORT_COLUMN_INFO = new ColumnInfo, Boolean>(EXPORT_COLUMN_NAME) { + @Nullable + @Override + public Boolean valueOf(ClasspathTableItem item) { + return item.isExported(); + } + + @Override + public void setValue(ClasspathTableItem item, Boolean value) { + item.setExported(value); + } + + @Override + public boolean isCellEditable(ClasspathTableItem item) { + return item.isExportable(); + } + + @Override + public Class getColumnClass() { + return Boolean.class; + } + }; private static final String SCOPE_COLUMN_NAME = ProjectBundle.message("modules.order.export.scope.column"); + private static final Comparator DEPENDENCY_SCOPE_COMPARATOR = new Comparator() { + @Override + public int compare(DependencyScope o1, DependencyScope o2) { + return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); + } + }; + private static final Comparator> CLASSPATH_ITEM_SCOPE_COMPARATOR = + new Comparator>() { + @Override + public int compare(ClasspathTableItem o1, ClasspathTableItem o2) { + return Comparing.compare(o1.getScope(), o2.getScope(), DEPENDENCY_SCOPE_COMPARATOR); + } + }; + private static final ColumnInfo, DependencyScope> SCOPE_COLUMN_INFO = new ColumnInfo, DependencyScope>(SCOPE_COLUMN_NAME) { + @Nullable + @Override + public DependencyScope valueOf(ClasspathTableItem item) { + return item.getScope(); + } + + @Override + public void setValue(ClasspathTableItem item, DependencyScope value) { + item.setScope(value); + } + + @Override + public boolean isCellEditable(ClasspathTableItem item) { + return item.isExportable(); + } + + @Override + public Class getColumnClass() { + return DependencyScope.class; + } + + @Nullable + @Override + public Comparator> getComparator() { + return CLASSPATH_ITEM_SCOPE_COMPARATOR; + } + }; public static final int EXPORT_COLUMN = 0; public static final int ITEM_COLUMN = 1; public static final int SCOPE_COLUMN = 2; - private final List> myItems = new ArrayList>(); private final ModuleConfigurationState myState; private StructureConfigurableContext myContext; public ClasspathTableModel(final ModuleConfigurationState state, StructureConfigurableContext context) { + super(EXPORT_COLUMN_INFO, new ClasspathTableItemClasspathColumnInfo(context), SCOPE_COLUMN_INFO); myState = state; myContext = context; init(); } + @Override + public RowSorter.SortKey getDefaultSortKey() { + return new RowSorter.SortKey(1, SortOrder.UNSORTED); + } + private ModifiableRootModel getModel() { return myState.getRootModel(); } @@ -56,111 +128,58 @@ class ClasspathTableModel extends AbstractTableModel implements ItemRemovable { public void init() { final OrderEntry[] orderEntries = getModel().getOrderEntries(); boolean hasJdkOrderEntry = false; + List> items = new ArrayList>(); for (final OrderEntry orderEntry : orderEntries) { if (orderEntry instanceof JdkOrderEntry) { hasJdkOrderEntry = true; } - addItem(ClasspathTableItem.createItem(orderEntry, myContext)); + items.add(ClasspathTableItem.createItem(orderEntry, myContext)); } if (!hasJdkOrderEntry) { - addItemAt(new InvalidJdkItem(), 0); + items.add(0, new InvalidJdkItem()); } - } - - public ClasspathTableItem getItemAt(int row) { - return myItems.get(row); - } - - public void addItem(ClasspathTableItem item) { - myItems.add(item); - } - - public void addItemAt(ClasspathTableItem item, int row) { - myItems.add(row, item); - } - - public ClasspathTableItem removeDataRow(int row) { - return myItems.remove(row); - } - - - @Override - public void removeRow(int row) { - removeDataRow(row); + setItems(items); } public void clear() { - myItems.clear(); + setItems(Collections.>emptyList()); } - @Override - public int getRowCount() { - return myItems.size(); - } + private static class ClasspathTableItemClasspathColumnInfo extends ColumnInfo, ClasspathTableItem> { + private final Comparator> myItemComparator; - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - final ClasspathTableItem item = myItems.get(rowIndex); - if (columnIndex == EXPORT_COLUMN) { - return item.isExported(); + public ClasspathTableItemClasspathColumnInfo(final StructureConfigurableContext context) { + super(""); + myItemComparator = new Comparator>() { + @Override + public int compare(ClasspathTableItem o1, ClasspathTableItem o2) { + String text1 = ClasspathPanelImpl.getCellAppearance(o1, context, false).getText(); + String text2 = ClasspathPanelImpl.getCellAppearance(o2, context, false).getText(); + return text1.compareToIgnoreCase(text2); + } + }; } - if (columnIndex == SCOPE_COLUMN) { - return item.getScope(); + + @Nullable + @Override + public Comparator> getComparator() { + return myItemComparator; } - if (columnIndex == ITEM_COLUMN) { + + @Nullable + @Override + public ClasspathTableItem valueOf(ClasspathTableItem item) { return item; } - LOG.error("Incorrect column index: " + columnIndex); - return null; - } - @Override - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - final ClasspathTableItem item = myItems.get(rowIndex); - if (columnIndex == EXPORT_COLUMN) { - item.setExported(((Boolean)aValue).booleanValue()); + @Override + public boolean isCellEditable(ClasspathTableItem item) { + return false; } - else if (columnIndex == SCOPE_COLUMN && aValue instanceof DependencyScope) { - item.setScope((DependencyScope) aValue); - } - } - @Override - public String getColumnName(int column) { - if (column == EXPORT_COLUMN) { - return EXPORT_COLUMN_NAME; - } - if (column == SCOPE_COLUMN) { - return SCOPE_COLUMN_NAME; - } - return ""; - } - - @Override - public Class getColumnClass(int column) { - if (column == EXPORT_COLUMN) { - return Boolean.class; - } - if (column == SCOPE_COLUMN) { - return DependencyScope.class; - } - if (column == ITEM_COLUMN) { + @Override + public Class getColumnClass() { return ClasspathTableItem.class; } - return super.getColumnClass(column); - } - - @Override - public int getColumnCount() { - return 3; - } - - @Override - public boolean isCellEditable(int row, int column) { - if (column == EXPORT_COLUMN || column == SCOPE_COLUMN) { - final ClasspathTableItem item = myItems.get(row); - return item != null && item.isExportable(); - } - return false; } } From 0a6983f77ab09313b6631e007584bb8463accfc9 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 30 Sep 2014 11:00:11 +0400 Subject: [PATCH 50/78] IDEA-105269 a new action to go to next edit location (opposite of 'last edit location') --- .../openapi/actionSystem/IdeActions.java | 3 + .../ide/actions/JumpToNextEditAction.java | 41 +++++++++ .../fileEditor/ex/IdeDocumentHistory.java | 4 +- .../impl/IdeDocumentHistoryImpl.java | 35 +++++--- .../src/messages/ActionsBundle.properties | 2 + .../src/idea/LangActions.xml | 2 +- .../src/idea/PlatformActions.xml | 1 + .../IdeDocumentHistoryFunctionalTest.java | 85 +++++++++++++++++++ 8 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/ide/actions/JumpToNextEditAction.java create mode 100644 platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/IdeDocumentHistoryFunctionalTest.java diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index 17efbb4d61df..a5325ad0a98e 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -242,6 +242,9 @@ public interface IdeActions { @NonNls String GROUP_GUI_DESIGNER_COMPONENT_TREE_POPUP = "GuiDesigner.ComponentTreePopupMenu"; @NonNls String GROUP_GUI_DESIGNER_PROPERTY_INSPECTOR_POPUP = "GuiDesigner.PropertyInspectorPopupMenu"; + @NonNls String ACTION_GOTO_LAST_CHANGE = "JumpToLastChange"; + @NonNls String ACTION_GOTO_NEXT_CHANGE = "JumpToNextChange"; + @NonNls String ACTION_GOTO_BACK = "Back"; @NonNls String ACTION_GOTO_FORWARD = "Forward"; @NonNls String ACTION_GOTO_DECLARATION = "GotoDeclaration"; diff --git a/platform/platform-impl/src/com/intellij/ide/actions/JumpToNextEditAction.java b/platform/platform-impl/src/com/intellij/ide/actions/JumpToNextEditAction.java new file mode 100644 index 000000000000..5890b4757cdb --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/actions/JumpToNextEditAction.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.actions; + +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +public class JumpToNextEditAction extends AnAction implements DumbAware { + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); + if (project == null) return; + IdeDocumentHistory.getInstance(project).navigateNextChange(); + } + + public void update(@NotNull AnActionEvent e){ + Presentation presentation = e.getPresentation(); + DataContext dataContext = e.getDataContext(); + Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + presentation.setEnabled(false); + return; + } + presentation.setEnabled(IdeDocumentHistory.getInstance(project).isNavigateNextChangeAvailable()); + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/IdeDocumentHistory.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/IdeDocumentHistory.java index 61e1a640612a..eeda21830d80 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/IdeDocumentHistory.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/IdeDocumentHistory.java @@ -1,6 +1,6 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,9 @@ public abstract class IdeDocumentHistory { public abstract boolean isForwardAvailable(); public abstract void navigatePreviousChange(); + public abstract void navigateNextChange(); public abstract boolean isNavigatePreviousChangeAvailable(); + public abstract boolean isNavigateNextChangeAvailable(); public abstract VirtualFile[] getChangedFiles(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java index b8f453453a50..88d83ffb63c1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java @@ -259,11 +259,10 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec } private void setCurrentChangePlace() { - final Pair selectedEditorWithProvider = getSelectedEditor(); - if (selectedEditorWithProvider == null) { + final PlaceInfo placeInfo = getCurrentPlaceInfo(); + if (placeInfo == null) { return; } - final PlaceInfo placeInfo = createPlaceInfo(selectedEditorWithProvider.getFirst(), selectedEditorWithProvider.getSecond ()); final VirtualFile file = placeInfo.getFile(); if (myChangedFilesInCurrentCommand.contains(file)) { @@ -318,13 +317,8 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec myStartIndex = 0; myCurrentIndex = 0; - if (myCurrentChangePlace != null) { - myCurrentChangePlace = null; - } - - if (myCommandStartPlace != null) { - myCommandStartPlace = null; - } + myCurrentChangePlace = null; + myCommandStartPlace = null; } @Override @@ -426,6 +420,27 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec } } + @Override + public void navigateNextChange() { + removeInvalidFilesFromStacks(); + if (myCurrentIndex >= myStartIndex + myChangePlaces.size() - 1) return; + int index = myCurrentIndex + 1; + final PlaceInfo info = myChangePlaces.get(index - myStartIndex); + + executeCommand(new Runnable() { + @Override + public void run() { + gotoPlaceInfo(info); + } + }, "", null); + myCurrentIndex = index; + } + + @Override + public boolean isNavigateNextChangeAvailable() { + return myCurrentIndex < myStartIndex + myChangePlaces.size() - 1; + } + private static boolean removeInvalidFilesFrom(@NotNull List backPlaces) { boolean removed = false; for (Iterator iterator = backPlaces.iterator(); iterator.hasNext();) { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 2a5e8e94aed1..58bc65a31f6e 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -486,6 +486,8 @@ action.Forward.text=For_ward action.Forward.description=Redo last undone navigation operation action.JumpToLastChange.text=Last Edit L_ocation action.JumpToLastChange.description=Move through the most recent change points +action.JumpToNextChange.text=Next Edit Location +action.JumpToNextChange.description=Move through the most recent change points action.PreviousOccurence.text=Previ_ous Occurrence action.PreviousOccurence.description=Navigate to the previous occurrence action.NextOccurence.text=Ne_xt Occurrence diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 7b4939d5e3b8..07a06b8300bb 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -108,7 +108,7 @@ - + diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index a8fb31cc1833..956a90ea3c14 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -325,6 +325,7 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/IdeDocumentHistoryFunctionalTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/IdeDocumentHistoryFunctionalTest.java new file mode 100644 index 000000000000..29eb7629488d --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/IdeDocumentHistoryFunctionalTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.fileEditor; + +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.testFramework.EditorTestUtil; + +public class IdeDocumentHistoryFunctionalTest extends HeavyFileEditorManagerTestCase { + public void testNavigateBetweenEditLocations() { + myFixture.configureByText(getTestName(false) + ".txt", + "line1\n" + + "\n" + + "\n" + + "\n" + + "line2\n" + + "\n" + + "\n" + + "\n" + + "line3"); + myFixture.type(' '); + moveCaret4LinesDown(); + myFixture.type(' '); + moveCaret4LinesDown(); + + EditorTestUtil.executeAction(getEditor(), IdeActions.ACTION_GOTO_LAST_CHANGE); + myFixture.checkResult(" line1\n" + + "\n" + + "\n" + + "\n" + + "l ine2\n" + + "\n" + + "\n" + + "\n" + + "line3"); + EditorTestUtil.executeAction(getEditor(), IdeActions.ACTION_GOTO_LAST_CHANGE); + myFixture.checkResult(" line1\n" + + "\n" + + "\n" + + "\n" + + "l ine2\n" + + "\n" + + "\n" + + "\n" + + "line3"); + EditorTestUtil.executeAction(getEditor(), IdeActions.ACTION_GOTO_NEXT_CHANGE); + myFixture.checkResult(" line1\n" + + "\n" + + "\n" + + "\n" + + "l ine2\n" + + "\n" + + "\n" + + "\n" + + "line3"); + EditorTestUtil.executeAction(getEditor(), IdeActions.ACTION_GOTO_NEXT_CHANGE); + myFixture.checkResult(" line1\n" + + "\n" + + "\n" + + "\n" + + "l ine2\n" + + "\n" + + "\n" + + "\n" + + "line3"); + } + + private void moveCaret4LinesDown() { + for (int i = 0; i < 4; i++) { + EditorTestUtil.executeAction(getEditor(), IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN); + } + } +} From 19be86339aceea4941aefadd0367eccfdc68758e Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Tue, 30 Sep 2014 11:04:31 +0400 Subject: [PATCH 51/78] EDU-140 Correct wording in the installation wizard EDU-139 Provides unified capitalization in the installation wizard --- python/edu/build/desktop.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/edu/build/desktop.ini b/python/edu/build/desktop.ini index 0ea32dec3569..c6f718aed9c8 100644 --- a/python/edu/build/desktop.ini +++ b/python/edu/build/desktop.ini @@ -23,7 +23,7 @@ Left=1 Right=-1 Top=35 Bottom=65 -Text=Choice Python version +Text=Choose Python version [Field 4] Type=RadioButton @@ -49,7 +49,7 @@ Left=1 Right=-1 Top=75 Bottom=105 -Text=Create Associations +Text=Create associations [Field 7] Type=checkbox From 23d921afcd0a65c9c10cc4a2a696f7017c7ecdfe Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Tue, 30 Sep 2014 11:12:05 +0400 Subject: [PATCH 52/78] EDU-139 Provides unified capitalization in the installation wizard --- build/conf/nsis/desktop.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/conf/nsis/desktop.ini b/build/conf/nsis/desktop.ini index 8f590b778e84..41eef313f4d9 100644 --- a/build/conf/nsis/desktop.ini +++ b/build/conf/nsis/desktop.ini @@ -23,7 +23,7 @@ Left=1 Right=-1 Top=35 Bottom=65 -Text=Create Associations +Text=Create associations [Field 4] Type=checkbox From 195b1afcc9d57d433adc6df65ae5eddc7a03abe7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 30 Sep 2014 08:34:35 +0200 Subject: [PATCH 53/78] cleanup --- .../stores/ModuleStateStorageManager.java | 4 ++-- .../impl/stores/ModuleStoreImpl.java | 6 ++--- .../diff/impl/mergeTool/MergeVersion.java | 24 +++++++++---------- .../openapi/project/ex/ProjectManagerEx.java | 2 +- .../diff/impl/patch/formove/PatchApplier.java | 24 +++++++++++++------ 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java index 3e0207c5e9e0..38558196e6ff 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStateStorageManager.java @@ -16,10 +16,10 @@ package com.intellij.openapi.components.impl.stores; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.StateStorageOperation; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; import com.intellij.openapi.module.Module; -import com.intellij.openapi.application.PathManager; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,7 +34,7 @@ class ModuleStateStorageManager extends StateStorageManagerImpl { } @Override - protected StorageData createStorageData(String storageSpec) { + protected StorageData createStorageData(@NotNull String storageSpec) { return new ModuleStoreImpl.ModuleFileData(ROOT_TAG_NAME, myModule); } diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java index f550fa1db3d0..ec07d50986bd 100644 --- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java @@ -159,12 +159,12 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM @Nullable @Override - public Set getChangedComponentNames(@NotNull StorageData storageData, @Nullable PathMacroSubstitutor substitutor) { - final ModuleFileData data = (ModuleFileData)storageData; + public Set getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) { + final ModuleFileData data = (ModuleFileData)newStorageData; if (!myOptions.equals(data.myOptions)) { return null; } - return super.getChangedComponentNames(storageData, substitutor); + return super.getChangedComponentNames(newStorageData, substitutor); } public void setOption(final String optionName, final String optionValue) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java index fd8e303cd680..f2194713a595 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java @@ -32,6 +32,7 @@ import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessor; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -42,7 +43,7 @@ import java.util.Set; public interface MergeVersion { Document createWorkingDocument(Project project); - void applyText(String text, Project project); + void applyText(@NotNull String text, Project project); @Nullable VirtualFile getFile(); @@ -91,7 +92,7 @@ public interface MergeVersion { } @Override - public void applyText(final String text, final Project project) { + public void applyText(@NotNull final String text, final Project project) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { @@ -105,24 +106,21 @@ public interface MergeVersion { }); } - protected void doApplyText(String text, Project project) { + protected void doApplyText(@NotNull String text, Project project) { setDocumentText(myDocument, text, DiffBundle.message("save.merge.result.command.name"), project); FileDocumentManager.getInstance().saveDocument(myDocument); - final VirtualFile file = getFile(); - reportProjectFileChangeIfNeeded(project, file); + reportProjectFileChangeIfNeeded(project, getFile()); } - public static void reportProjectFileChangeIfNeeded(Project project, @Nullable VirtualFile file) { - if (file != null && !file.isDirectory()) { - if (ProjectCoreUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file)) { - ProjectManagerEx.getInstanceEx().saveChangedProjectFile(file, project); - } + public static void reportProjectFileChangeIfNeeded(@Nullable Project project, @Nullable VirtualFile file) { + if (project != null && file != null && !file.isDirectory() && (ProjectCoreUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file))) { + ProjectManagerEx.getInstanceEx().saveChangedProjectFile(file, project); } } @Nullable - public static Runnable prepareToReportChangedProjectFiles(final Project project, final Collection files) { + public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, final Collection files) { final Set vfs = new HashSet(); for (VirtualFile vf : files) { if (vf != null && ! vf.isDirectory()) { @@ -157,7 +155,7 @@ public interface MergeVersion { return importProvider != null && importProvider.lookForProjectsInDirectory(); } - protected void doRestoreOriginalContent(Project project) { + protected void doRestoreOriginalContent(@Nullable Project project) { setDocumentText(myDocument, myTextBeforeMerge, "", project); } @@ -181,7 +179,7 @@ public interface MergeVersion { return file.getFileType(); } - private static void setDocumentText(final Document document, final String text, String name, Project project) { + private static void setDocumentText(@NotNull final Document document, @NotNull final String text, @Nullable String name, @Nullable Project project) { CommandProcessor.getInstance().executeCommand(project, new Runnable() { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java index 0273c7dbf2ee..05b894248b8e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.java @@ -48,7 +48,7 @@ public abstract class ProjectManagerEx extends ProjectManager { public abstract boolean canClose(Project project); - public abstract void saveChangedProjectFile(@NotNull VirtualFile file, @Nullable Project project); + public abstract void saveChangedProjectFile(@NotNull VirtualFile file, @NotNull Project project); public abstract boolean isFileSavedToBeReloaded(VirtualFile file); diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java index 9f5901788e76..ca2dc227b5bd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java @@ -41,7 +41,7 @@ import com.intellij.openapi.vcs.changes.patch.ApplyPatchAction; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.ReadonlyStatusHandler; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.RefreshQueue; import com.intellij.util.Consumer; @@ -72,7 +72,7 @@ public class PatchApplier { @Nullable private final String myLeftConflictPanelTitle; @Nullable private final String myRightConflictPanelTitle; - public PatchApplier(final Project project, final VirtualFile baseDirectory, final List patches, + public PatchApplier(@NotNull Project project, final VirtualFile baseDirectory, final List patches, @Nullable final Consumer> toTargetListsMover, final CustomBinaryPatchApplier customForBinaries, final CommitContext commitContext, boolean reverseConflict, @Nullable String leftConflictPanelTitle, @Nullable String rightConflictPanelTitle) { @@ -87,6 +87,7 @@ public class PatchApplier { myRightConflictPanelTitle = rightConflictPanelTitle; myRemainingPatches = new ArrayList(); myVerifier = new PathsVerifier(myProject, myBaseDirectory, myPatches, new PathsVerifier.BaseMapper() { + @Override @Nullable public VirtualFile getFile(FilePatch patch, String path) { return PathMerger.getFile(myBaseDirectory, path); @@ -174,11 +175,13 @@ public class PatchApplier { final ApplyPatchStatus applyStatus; try { applyStatus = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override public ApplyPatchStatus compute() { final Ref refStatus = new Ref(ApplyPatchStatus.FAILURE); try { setConfirmationToDefault(); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + @Override public void run() { if (! createFiles()) { refStatus.set(ApplyPatchStatus.FAILURE); @@ -258,6 +261,7 @@ public class PatchApplier { final Ref refStatus = new Ref(null); try { CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override public void run() { for (PatchApplier applier : group) { if (! applier.createFiles()) { @@ -287,7 +291,7 @@ public class PatchApplier { } directlyAffected.addAll(trigger.getAffected()); final Consumer> mover = localChangeList == null ? null : createMover(project, localChangeList); - PatchApplier.refreshPassedFilesAndMoveToChangelist(project, null, directlyAffected, indirectlyAffected, mover, false); + refreshPassedFilesAndMoveToChangelist(project, null, directlyAffected, indirectlyAffected, mover, false); showApplyStatus(project, result); return result; } @@ -360,7 +364,7 @@ public class PatchApplier { return myVerifier.getAllAffected(); } - public static void refreshPassedFilesAndMoveToChangelist(final Project project, final ContinuationContext context, + public static void refreshPassedFilesAndMoveToChangelist(@NotNull final Project project, final ContinuationContext context, final Collection directlyAffected, final Collection indirectlyAffected, final Consumer> targetChangelistMover, final boolean systemOperation) { if (context != null) { @@ -368,6 +372,7 @@ public class PatchApplier { } final Runnable scheduleProjectFilesReload = systemOperation ? EmptyRunnable.getInstance() : new Runnable() { + @Override public void run() { final Runnable projectFilesReload = MergeVersion.MergeDocumentVersion.prepareToReportChangedProjectFiles(project, ObjectsConvertor.fp2vf(directlyAffected)); @@ -381,7 +386,8 @@ public class PatchApplier { if (projectFilesReloadTaskDescriptor != null) { if (context != null) { context.last(projectFilesReloadTaskDescriptor); - } else { + } + else { SwingUtilities.invokeLater(projectFilesReload); } } @@ -393,6 +399,7 @@ public class PatchApplier { lfs.refreshAndFindFileByIoFile(filePath.getIOFile()); } RefreshQueue.getInstance().refresh(false, true, new Runnable() { + @Override public void run() { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override @@ -413,6 +420,7 @@ public class PatchApplier { }, InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, VcsBundle.message("change.lists.manager.move.changes.to.list"), new Consumer() { + @Override public void consume(final VcsDirtyScopeManager vcsDirtyScopeManager) { vcsDirtyScopeManager.filePathsDirty(directlyAffected, null); vcsDirtyScopeManager.filesDirty(indirectlyAffected, null); @@ -491,7 +499,7 @@ public class PatchApplier { return status; } - protected static void showApplyStatus(final Project project, final ApplyPatchStatus status) { + protected static void showApplyStatus(@NotNull Project project, final ApplyPatchStatus status) { if (status == ApplyPatchStatus.ALREADY_APPLIED) { showError(project, VcsBundle.message("patch.apply.already.applied"), false); } @@ -508,7 +516,7 @@ public class PatchApplier { } private boolean makeWritable(final List filesToMakeWritable) { - final VirtualFile[] fileArray = VfsUtil.toVirtualFileArray(filesToMakeWritable); + final VirtualFile[] fileArray = VfsUtilCore.toVirtualFileArray(filesToMakeWritable); final ReadonlyStatusHandler.OperationStatus readonlyStatus = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(fileArray); return (! readonlyStatus.hasReadonlyFiles()); } @@ -537,6 +545,7 @@ public class PatchApplier { } final String title = VcsBundle.message("patch.apply.dialog.title"); final Runnable messageShower = new Runnable() { + @Override public void run() { if (error) { Messages.showErrorDialog(project, message, title); @@ -547,6 +556,7 @@ public class PatchApplier { } }; WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() { + @Override public void run() { messageShower.run(); } From fab4c3efbe5ff7c369f0f62a4ab76b103257ca11 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 30 Sep 2014 09:32:57 +0200 Subject: [PATCH 54/78] fix ChooseByNameTest --- .../com/intellij/navigation/ChooseByNameTest.groovy | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy index 9c378a1e50cf..0a5b65deb372 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy +++ b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy @@ -247,10 +247,12 @@ class Intf { List elements = ['empty'] def semaphore = new Semaphore() semaphore.down() - popup.scheduleCalcElements(text, checkboxState, ModalityState.NON_MODAL, { set -> - elements = set as List - semaphore.up() - } as Consumer>) + edt { + popup.scheduleCalcElements(text, checkboxState, ModalityState.NON_MODAL, { set -> + elements = set as List + semaphore.up() + } as Consumer>) + } if (!semaphore.waitFor(10000)) { printThreadDump() fail() From d00110a4143426309aab48c0cc0fec3afa1e6612 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 30 Sep 2014 11:11:40 +0400 Subject: [PATCH 55/78] classpath panel: combobox fixed --- .../roots/ui/configuration/classpath/ClasspathPanelImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index 9a65ba9f80cf..4b80cc59e557 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -46,6 +46,7 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryPro import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.SdkProjectStructureElement; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.ComboBoxTableRenderer; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopup; @@ -129,7 +130,7 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { myEntryTable.setDefaultRenderer(ClasspathTableItem.class, new TableItemRenderer(getStructureConfigurableContext())); myEntryTable.setDefaultRenderer(Boolean.class, new ExportFlagRenderer(myEntryTable.getDefaultRenderer(Boolean.class))); - JComboBox scopeEditor = new JComboBox(new EnumComboBoxModel(DependencyScope.class)); + JComboBox scopeEditor = new ComboBox(new EnumComboBoxModel(DependencyScope.class)); myEntryTable.setDefaultEditor(DependencyScope.class, new DefaultCellEditor(scopeEditor)); myEntryTable.setDefaultRenderer(DependencyScope.class, new ComboBoxTableRenderer(DependencyScope.values()) { @Override From b72627d0f736791c19475f3497a3f7eb58c1e934 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 30 Sep 2014 09:59:31 +0200 Subject: [PATCH 56/78] more debug logging on p4 rename/move processing (IDEA-130487) --- .../src/com/intellij/openapi/vcs/VcsVFSListener.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java index d39a18a6137f..078fd0c97c9f 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -58,6 +58,11 @@ public abstract class VcsVFSListener implements Disposable { myNewPath = newPath; myFile = file; } + + @Override + public String toString() { + return "MovedFileInfo{myNewPath=" + myNewPath + ", myFile=" + myFile + '}'; + } } protected final Project myProject; @@ -267,6 +272,7 @@ public abstract class VcsVFSListener implements Disposable { protected void processMovedFile(VirtualFile file, String newParentPath, String newName) { final FileStatus status = FileStatusManager.getInstance(myProject).getStatus(file); + LOG.debug("Checking moved file " + file + "; status=" + status); if (status == FileStatus.IGNORED) { if (file.getParent() != null) { myDirtyFiles.add(file.getParent()); @@ -284,6 +290,7 @@ public abstract class VcsVFSListener implements Disposable { } } if (!foundExistingInfo) { + LOG.debug("Registered moved file " + file); myMovedFiles.add(new MovedFileInfo(file, newPath)); } } @@ -291,6 +298,7 @@ public abstract class VcsVFSListener implements Disposable { private void executeMoveRename() { final List movedFiles = new ArrayList(myMovedFiles); + LOG.debug("executeMoveRename " + movedFiles); myMovedFiles.clear(); performMoveRename(movedFiles); } @@ -373,6 +381,7 @@ public abstract class VcsVFSListener implements Disposable { if (isEventIgnored(event, true)) return; final VirtualFile file = event.getFile(); final AbstractVcs newVcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(event.getNewParent()); + LOG.debug("beforeFileMovement " + event + " into " + newVcs); if (newVcs == myVcs) { addFileToMove(file, event.getNewParent().getPath(), file.getName()); } @@ -393,6 +402,7 @@ public abstract class VcsVFSListener implements Disposable { @Override public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { if (!isEventIgnored(event, false) && event.getPropertyName().equalsIgnoreCase(VirtualFile.PROP_NAME)) { + LOG.debug("before file rename " + event); String oldName = (String)event.getOldValue(); String newName = (String)event.getNewValue(); // in order to force a reparse of a file, the rename event can be fired with old name equal to new name - From 2fe23a1854fe0c132381b41f32405a4ef1a7dc3a Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 30 Sep 2014 12:03:02 +0400 Subject: [PATCH 57/78] testData fix due to error reporting changes in GPUB --- json/tests/testData/psi/IncompleteObjectProperties.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/json/tests/testData/psi/IncompleteObjectProperties.txt b/json/tests/testData/psi/IncompleteObjectProperties.txt index 4187382bfd1e..62b4a2188e72 100644 --- a/json/tests/testData/psi/IncompleteObjectProperties.txt +++ b/json/tests/testData/psi/IncompleteObjectProperties.txt @@ -14,14 +14,14 @@ JsonFile: IncompleteObjectProperties.json JsonProperty JsonStringLiteral PsiElement(DOUBLE_QUOTED_STRING)('"bar"') - PsiErrorElement:':' expected, got ',' - + PsiErrorElement:':' expected, got ',' + PsiElement(,)(',') PsiWhiteSpace('\n ') JsonProperty JsonStringLiteral PsiElement(DOUBLE_QUOTED_STRING)('"baz"') - PsiErrorElement:':' expected, got '}' - + PsiErrorElement:':' expected, got '}' + PsiWhiteSpace('\n') PsiElement(})('}') \ No newline at end of file From 31ae096330987b679056c6ac60ea096a9122b058 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 30 Sep 2014 12:28:33 +0400 Subject: [PATCH 58/78] +gzipped --- spellchecker/src/com/intellij/spellchecker/jetbrains.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 8bead63e93a1..b7738ec08ef8 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -168,8 +168,9 @@ getters giud globals google -gzip gruntfile +gzip +gzipped hamcrest hardcoded hardlink From e7c7e9d55fe5cef7c675b52d263ef7b05b2f7f92 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 29 Sep 2014 22:24:38 +0400 Subject: [PATCH 59/78] EA-60966 diff: dispose RangeHighlighter from EDT --- .../openapi/vcs/ex/LineStatusTracker.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 1f8d87d70b16..fe363d920bcd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -212,12 +212,25 @@ public class LineStatusTracker { public void release() { synchronized (myLock) { + myReleased = true; if (myDocumentListener != null) { myDocument.removeDocumentListener(myDocumentListener); } - removeAnathema(); - removeHighlightersFromMarkupModel(); - myReleased = true; + + if (myApplication.isDispatchThread()) { + removeAnathema(); + removeHighlightersFromMarkupModel(); + } + else { + invalidateRanges(); + myApplication.invokeLater(new Runnable() { + @Override + public void run() { + removeAnathema(); + removeHighlightersFromMarkupModel(); + } + }); + } } } @@ -259,6 +272,8 @@ public class LineStatusTracker { } private void removeHighlightersFromMarkupModel() { + myApplication.assertIsDispatchThread(); + synchronized (myLock) { for (Range range : myRanges) { if (range.getHighlighter() != null) { @@ -270,6 +285,14 @@ public class LineStatusTracker { } } + private void invalidateRanges() { + synchronized (myLock) { + for (Range range : myRanges) { + range.invalidate(); + } + } + } + public void finishBulkUpdate() { synchronized (myLock) { if (myReleased) return; From 7870b304d1d6558aa7f33d27f008b9061f23bd8c Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 30 Sep 2014 12:51:12 +0400 Subject: [PATCH 60/78] external build: added test for compilation of module which depends on app server library (IDEA-130520) --- .../intellij/compiler/CompilerTestUtil.java | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java index e5a9ee47daed..78c840ad2e65 100644 --- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java +++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java @@ -2,23 +2,30 @@ package com.intellij.compiler; import com.intellij.compiler.impl.javaCompiler.javac.JavacConfiguration; import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.application.impl.ApplicationImpl; +import com.intellij.openapi.components.ExportableApplicationComponent; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.impl.stores.StateStorageManager; import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; -import com.intellij.openapi.projectRoots.impl.ProjectJdkTableImpl; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.NamedJDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -28,7 +35,6 @@ import org.jdom.Element; import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions; import org.jetbrains.jps.model.serialization.JDomSerializationUtil; -import org.jetbrains.jps.model.serialization.JpsGlobalLoader; import java.io.File; import java.io.IOException; @@ -59,28 +65,47 @@ public class CompilerTestUtil { } public static void saveApplicationSettings() { - try { - ProjectJdkTableImpl table = (ProjectJdkTableImpl)ProjectJdkTable.getInstance(); - Element root = new Element("application"); - root.addContent(JDomSerializationUtil.createComponentElement(JpsGlobalLoader.SDK_TABLE_COMPONENT_NAME).addContent(table.getState().cloneContent())); - saveApplicationComponent(root, ((ProjectJdkTableImpl)ProjectJdkTable.getInstance()).getExportFiles()[0]); + saveApplicationComponent(ProjectJdkTable.getInstance()); + saveApplicationComponent(FileTypeManager.getInstance()); + } - FileTypeManagerImpl fileTypeManager = (FileTypeManagerImpl)FileTypeManager.getInstance(); - Element fileTypesComponent = JDomSerializationUtil.createComponentElement(fileTypeManager.getComponentName()); - fileTypeManager.writeExternal(fileTypesComponent); - saveApplicationComponent(new Element("application").addContent(fileTypesComponent), PathManager.getOptionsFile(fileTypeManager)); - } - catch (IOException e) { - throw new RuntimeException(e); + public static void saveApplicationComponent(Object appComponent) { + try { + final File file; + String componentName; + State state = appComponent.getClass().getAnnotation(State.class); + if (state != null) { + componentName = state.name(); + Storage lastStorage = state.storages()[state.storages().length - 1]; + StateStorageManager storageManager = ((ApplicationImpl)ApplicationManager.getApplication()).getStateStore().getStateStorageManager(); + file = new File(storageManager.expandMacros(lastStorage.file())); + } + else if (appComponent instanceof ExportableApplicationComponent && appComponent instanceof NamedJDOMExternalizable) { + componentName = ((ExportableApplicationComponent)appComponent).getComponentName(); + file = PathManager.getOptionsFile((NamedJDOMExternalizable)appComponent); + } + else { + throw new AssertionError( appComponent.getClass() + " doesn't have @State annotation and doesn't implement ExportableApplicationComponent"); + } + + Element root = new Element("application"); + Element element = JDomSerializationUtil.createComponentElement(componentName); + if (appComponent instanceof JDOMExternalizable) { + ((JDOMExternalizable)appComponent).writeExternal(element); + } + else { + element.addContent(((PersistentStateComponent)appComponent).getState().cloneContent()); + } + root.addContent(element); + FileUtil.createParentDirs(file); + JDOMUtil.writeDocument(new Document(root), file, SystemProperties.getLineSeparator()); } catch (WriteExternalException e) { throw new RuntimeException(e); } - } - - private static void saveApplicationComponent(Element root, final File file) throws IOException { - FileUtil.createParentDirs(file); - JDOMUtil.writeDocument(new Document(root), file, SystemProperties.getLineSeparator()); + catch (IOException e) { + throw new RuntimeException(e); + } } public static void enableExternalCompiler() { From 75f1f14e8ca2673457c53617254a688175777190 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Sep 2014 18:28:24 +0200 Subject: [PATCH 61/78] anonymous type methods: remove too much intelligence (IDEA-130498) --- .../src/com/intellij/psi/scope/util/PsiScopesUtil.java | 7 ++++++- .../HiddenMethodsOfAnonymousClass.java | 9 +++++++++ .../codeInsight/daemon/GenericsHighlightingTest.java | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/HiddenMethodsOfAnonymousClass.java diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java index 2c2d8b2e1256..cbfff3ed3534 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java @@ -323,7 +323,12 @@ public class PsiScopesUtil { if (refMethods.length > 0) { final PsiClass baseClass = PsiUtil.resolveClassInType(type); if (baseClass != null && !hasCovariantOverriding(baseClass, refMethods)) { - type = initializer.getType(); + for (PsiMethod method : refMethods) { + if (method.findSuperMethods(baseClass).length > 0) { + type = initializer.getType(); + break; + } + } } } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/HiddenMethodsOfAnonymousClass.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/HiddenMethodsOfAnonymousClass.java new file mode 100644 index 000000000000..f1ecb50a5662 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/HiddenMethodsOfAnonymousClass.java @@ -0,0 +1,9 @@ +class Example { + public static void main(String[] args) { + final Runnable r = new Runnable() { + public void run() {} + public void m2() {} + }; + r.m2(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index ac57a71e9c9f..fde013dca76d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -380,6 +380,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { //jdk should propagate LL 1.4 but actually it provides LL 1.7?! public void testCastObjectToIntJdk14() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_4, false); } + public void testHiddenMethodsOfAnonymousClass() throws Exception { + doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); + } + public void testJavaUtilCollections_NoVerify() throws Exception { PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); assertNotNull(collectionsClass); From 95e3310d7a2b697d6f1655c777ee3a99d93414d2 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 30 Sep 2014 10:32:44 +0200 Subject: [PATCH 62/78] IDEA-130540 Convert TestCase to TestNG duplicates all annotations --- .../theoryinpractice/testng/inspection/JUnitConvertTool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java index 212c6aeacaeb..160ae1d0f0f1 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java @@ -102,8 +102,9 @@ public class JUnitConvertTool extends BaseJavaLocalInspectionTool { else { if (TestNGUtil.containsJunitAnnotions(method)) { convertJunitAnnotions(factory, method); + } else { + addMethodAnnotations(factory, method); } - addMethodAnnotations(factory, method); } } From 0400683097e485a2d203270a4a15196e60f82bd8 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 30 Sep 2014 10:57:00 +0200 Subject: [PATCH 63/78] IDEA-130544 Convert TestCase to TestNG does not convert assertions --- .../testng/inspection/JUnitConvertTool.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java index 160ae1d0f0f1..546a891582c5 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/JUnitConvertTool.java @@ -172,8 +172,10 @@ public class JUnitConvertTool extends BaseJavaLocalInspectionTool { //if it's a 3 arg, the error message goes at the end PsiElement inserted = null; if (expressions.length == 2) { + final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression(); + final String text = "org.testng." + (qualifierExpression == null ? "Assert." : "") + methodCall.getText() + ";"; inserted = methodCallStatement - .replace(factory.createStatementFromText("org.testng.Assert." + methodCall.getText() + ";", methodCall.getParent())); + .replace(factory.createStatementFromText(text, methodCall.getParent())); } else if (expressions.length == 3) { @NonNls String call = "org.testng.Assert." + methodName + '(' + expressions[2].getText() + ", " + expressions[1].getText() + @@ -262,7 +264,18 @@ public class JUnitConvertTool extends BaseJavaLocalInspectionTool { if (!(element instanceof PsiMethodCallExpression)) return false; final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element; final PsiMethod method = methodCall.resolveMethod(); - return method != null && "junit.framework.Assert".equals(method.getContainingClass().getQualifiedName()); + if (method != null) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass != null) { + final String qualifiedName = containingClass.getQualifiedName(); + if ("junit.framework.Assert".equals(qualifiedName) || + "org.junit.Assert".equals(qualifiedName) || + "junit.framework.TestCase".equals(qualifiedName)) { + return true; + } + } + } + return false; } }); PsiMethodCallExpression[] expressions = new PsiMethodCallExpression[methodCalls.length]; From ff22465de0958af75bba8fcce2cd63be6d25da36 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Tue, 30 Sep 2014 13:30:30 +0400 Subject: [PATCH 64/78] bug with set value in templates fixed --- python/helpers/pydev/pydevd_comm.py | 2 +- .../pydev/pydevd_plugins/django_debug.py | 8 ++++ .../pydev/pydevd_plugins/jinja2_debug.py | 46 ++++++++++++------- python/helpers/pydev/pydevd_trace_api.py | 5 +- python/helpers/pydev/pydevd_vars.py | 10 ++-- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 92a588cbaa93..27fca26e4e3b 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -970,7 +970,7 @@ class InternalChangeVariable(InternalThreadCommand): def doIt(self, dbg): """ Converts request into python variable """ try: - result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression) + result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression, dbg) xml = "" xml += pydevd_vars.varToXML(result, "") xml += "" diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py index 45d865985048..3fa341865246 100644 --- a/python/helpers/pydev/pydevd_plugins/django_debug.py +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -256,6 +256,14 @@ class DjangoTemplateFrame: d[k] = value +def change_variable(plugin, frame, attr, expression): + if isinstance(frame, DjangoTemplateFrame): + result = eval(expression, frame.f_globals, frame.f_locals) + frame.changeVariable(attr, result) + return result + return False + + def _is_django_exception_break_context(frame): try: name = frame.f_code.co_name diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py index feb31804dd7b..f5857ea4c88f 100644 --- a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -101,11 +101,6 @@ def _find_jinja2_render_frame(frame): return frame -def _change_variable(plugin, pydb, frame, attr, expression): - if isinstance(frame, Jinja2TemplateFrame): - result = eval(expression, frame.f_globals, frame.f_locals) - frame.changeVariable(attr, result) - #======================================================================================================================= # Jinja2 Frame @@ -121,29 +116,46 @@ class Jinja2TemplateFrame: self.back_context = frame.f_locals['context'] self.f_code = FCode('template', file_name) self.f_lineno = _get_jinja2_template_line(frame) - self.f_back = _find_render_function_frame(frame) + self.f_back = frame self.f_globals = {} self.f_locals = self.collect_context(frame) self.f_trace = None def collect_context(self, frame): res = {} + for k, v in frame.f_locals.items(): + if not k.startswith('l_'): + res[k] = v + elif v and not _is_missing(v): + res[k[2:]] = v if self.back_context is not None: for k, v in self.back_context.items(): res[k] = v - for k, v in frame.f_locals.items(): - if not k.startswith('l_'): - if not k in res: - #local variables should shadow globals from context - res[k] = v - elif v and not _is_missing(v): - res[k[2:]] = v return res - def changeVariable(self, name, value): - for k, v in self.back_context.items(): - if k == name: - self.back_context.vars[k] = value + def changeVariable(self, frame, name, value): + in_vars_or_parents = False + if name in frame.f_locals['context'].parent: + self.back_context.parent[name] = value + in_vars_or_parents = True + if name in frame.f_locals['context'].vars: + self.back_context.vars[name] = value + in_vars_or_parents = True + + l_name = 'l_' + name + if l_name in frame.f_locals: + if in_vars_or_parents: + frame.f_locals[l_name] = self.back_context.resolve(name) + else: + frame.f_locals[l_name] = value + + +def change_variable(plugin, frame, attr, expression): + if isinstance(frame, Jinja2TemplateFrame): + result = eval(expression, frame.f_globals, frame.f_locals) + frame.changeVariable(frame.f_back, attr, result) + return result + return False def _is_missing(item): diff --git a/python/helpers/pydev/pydevd_trace_api.py b/python/helpers/pydev/pydevd_trace_api.py index 542e20daca97..b2bdaff46e3a 100644 --- a/python/helpers/pydev/pydevd_trace_api.py +++ b/python/helpers/pydev/pydevd_trace_api.py @@ -35,4 +35,7 @@ def suspend(plugin, pydb, thread, frame): return None def exception_break(plugin, pydb, pydb_frame, frame, args, arg): - return None \ No newline at end of file + return None + +def change_variable(plugin, frame, attr, expression): + return False diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index b9e4d427dfba..b2df11eb410e 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -352,7 +352,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): del updated_globals del frame -def changeAttrExpression(thread_id, frame_id, attr, expression): +def changeAttrExpression(thread_id, frame_id, attr, expression, dbg): '''Changes some attribute in a given frame. ''' frame = findFrame(thread_id, frame_id) @@ -362,10 +362,10 @@ def changeAttrExpression(thread_id, frame_id, attr, expression): try: expression = expression.replace('@LINE@', '\n') - # if isinstance(frame, DjangoTemplateFrame): # TODO: implemente for plugins - # result = eval(expression, frame.f_globals, frame.f_locals) - # frame.changeVariable(attr, result) - # return + if dbg.plugin: + result = dbg.plugin.change_variable(frame, attr, expression) + if result: + return result if attr[:7] == "Globals": attr = attr[8:] From bbb746b37a5e5335be621049af5337a941cd6efb Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 30 Sep 2014 11:31:47 +0200 Subject: [PATCH 65/78] make IG test light --- .../design_for_extension/DesignForExtension.java | 2 +- .../security/design_for_extension/expected.xml | 9 --------- .../security/DesignForExtensionInspectionTest.java | 14 ++++++++++---- 3 files changed, 11 insertions(+), 14 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/DesignForExtension.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/DesignForExtension.java index c6639e9758e9..dab95763a6c4 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/DesignForExtension.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/DesignForExtension.java @@ -3,7 +3,7 @@ package com.siyeh.igtest.security.design_for_extension; class DesignForExtension { - public boolean equals(Object o) { + public boolean equals(Object o) { return true; } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/expected.xml deleted file mode 100644 index d1054673ef8b..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/security/design_for_extension/expected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - DesignForExtension.java - 6 - Design for extension - Method <code>equals()</code> may be overridden and its functionality ignored #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/security/DesignForExtensionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/security/DesignForExtensionInspectionTest.java index 590cdac89b11..689be916649b 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/security/DesignForExtensionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/security/DesignForExtensionInspectionTest.java @@ -1,10 +1,16 @@ package com.siyeh.ig.security; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class DesignForExtensionInspectionTest extends IGInspectionTestCase { +public class DesignForExtensionInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - doTest("com/siyeh/igtest/security/design_for_extension", new DesignForExtensionInspection()); + public void testDesignForExtension() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new DesignForExtensionInspection(); } } \ No newline at end of file From fb27ac0931cb40021116550fa02f25d28437230d Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 30 Sep 2014 11:32:35 +0200 Subject: [PATCH 66/78] IDEA-130360 (Add quick fix to "Design for extension" inspection) --- .../DesignForExtensionInspection.java | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/security/DesignForExtensionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/security/DesignForExtensionInspection.java index 5a90d4b3fad8..d2c182c276ff 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/security/DesignForExtensionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/security/DesignForExtensionInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,17 @@ package com.siyeh.ig.security; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.intellij.psi.util.FileTypeUtils; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class DesignForExtensionInspection extends BaseInspection { @@ -38,6 +43,48 @@ public class DesignForExtensionInspection extends BaseInspection { "design.for.extension.problem.descriptor"); } + @Nullable + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + final PsiMethod method = (PsiMethod)infos[0]; + if (MethodUtils.isOverridden(method)) { + return null; + } + return new MakeMethodFinalFix(method.getName()); + } + + private static class MakeMethodFinalFix extends InspectionGadgetsFix { + + private String myMethodName; + + public MakeMethodFinalFix(String methodName) { + myMethodName = methodName; + } + + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message("make.method.final.fix.name", myMethodName); + } + + @NotNull + @Override + public String getFamilyName() { + return "Make method 'final'"; + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement().getParent(); + if (!(element instanceof PsiMethod)) { + return; + } + final PsiMethod method = (PsiMethod)element; + final PsiModifierList modifierList = method.getModifierList(); + modifierList.setModifierProperty(PsiModifier.FINAL, true); + } + } + @Override public BaseInspectionVisitor buildVisitor() { return new DesignForExtensionVisitor(); @@ -82,7 +129,7 @@ public class DesignForExtensionInspection extends BaseInspection { if (statements.length == 0) { return; } - registerMethodError(method); + registerMethodError(method, method); } } } \ No newline at end of file From 9d0ddbd8eb480b5cf7488cabb50866c5a8260386 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 30 Sep 2014 11:33:02 +0200 Subject: [PATCH 67/78] EA-57845 --- .../src/com/intellij/usages/UsageViewPresentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java b/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java index c597eea48db0..ee4f0b63cc8a 100644 --- a/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java +++ b/platform/usageView/src/com/intellij/usages/UsageViewPresentation.java @@ -28,7 +28,7 @@ import java.util.List; */ public class UsageViewPresentation { private String myTabText; - private String myScopeText; + private String myScopeText = ""; // Default value. to be overwritten in most cases. private String myUsagesString; private String myTargetsNodeText = UsageViewBundle.message("node.targets"); // Default value. to be overwritten in most cases. private String myNonCodeUsagesString = UsageViewBundle.message("node.non.code.usages"); From 3bf85698191e4b7c95957c783aead20b87640c7f Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 30 Sep 2014 13:10:42 +0400 Subject: [PATCH 68/78] IDEA-130503 Emacs cut to end of line broken make all 'delete' actions work consistently (other actions were changed as per IDEA-121896) --- .../openapi/editor/actions/CutLineActionHandler.java | 5 ----- .../openapi/editor/actions/DeleteToWordEndAction.java | 9 ++------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineActionHandler.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineActionHandler.java index f09a53c8ae99..b64040de3ef6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineActionHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineActionHandler.java @@ -56,11 +56,6 @@ class CutLineActionHandler extends EditorWriteActionHandler { int lineEndOffset = doc.getLineEndOffset(lineNumber); int lineStartOffset = doc.getLineStartOffset(lineNumber); - if (editor.isColumnMode() && editor.getCaretModel().supportsMultipleCarets() - && caretOffset == (myToLineStart ? lineStartOffset : lineEndOffset)) { - return; - } - int start; int end; if (myToLineStart) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteToWordEndAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteToWordEndAction.java index 5785f01feb33..b97e0cdaa2d9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteToWordEndAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/DeleteToWordEndAction.java @@ -18,6 +18,7 @@ package com.intellij.openapi.editor.actions; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; @@ -45,16 +46,10 @@ public class DeleteToWordEndAction extends TextComponentEditorAction { } @Override - public void executeWriteAction(Editor editor, DataContext dataContext) { + public void executeWriteAction(Editor editor, Caret caret, DataContext dataContext) { CommandProcessor.getInstance().setCurrentCommandGroupId(EditorActionUtil.DELETE_COMMAND_GROUP); CopyPasteManager.getInstance().stopKillRings(); - int lineNumber = editor.getCaretModel().getLogicalPosition().line; - if (editor.isColumnMode() && editor.getCaretModel().supportsMultipleCarets() - && editor.getCaretModel().getOffset() == editor.getDocument().getLineEndOffset(lineNumber)) { - return; - } - boolean camelMode = editor.getSettings().isCamelWords(); if (myNegateCamelMode) { camelMode = !camelMode; From b14bcbbddb89e8bcb1d12a4fde5de69ac2495982 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskay" Date: Tue, 30 Sep 2014 14:02:00 +0400 Subject: [PATCH 69/78] IDEA-129447 Arrangement: scroll UI into view when editing rule --- .../action/AbstractArrangementRuleAction.java | 13 +------------ .../match/ArrangementMatchingRulesControl.java | 15 +++++++++++++++ .../util/ArrangementListRowDecorator.java | 1 + 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java index 1e5a84da3f8d..ec700f7e2363 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java @@ -35,17 +35,6 @@ public abstract class AbstractArrangementRuleAction extends AnAction { } protected void scrollRowToVisible(@NotNull ArrangementMatchingRulesControl control, int row) { - final Rectangle rect = control.getCellRect(row, 0, false); - if (row != control.getEditingRow() - 1) { - control.scrollRectToVisible(rect); - } - else { - final Rectangle editorRect = control.getCellRect(row + 1, 0, false); - if(!rect.isEmpty() && !editorRect.isEmpty()) { - final int height = (int)(rect.getHeight() + editorRect.getHeight()); - final Rectangle visibleRect = new Rectangle((int)rect.getX(), (int)rect.getY(), (int)rect.getWidth(), height); - control.scrollRectToVisible(visibleRect); - } - } + control.scrollRowToVisible(row); } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java index 5889df54e1b1..6f5963fb4dac 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java @@ -329,6 +329,21 @@ public class ArrangementMatchingRulesControl extends JBTable { showEditor(myEditor, rowToEdit); } + public void scrollRowToVisible(int row) { + final Rectangle rect = getCellRect(row, 0, false); + if (row != getEditingRow() - 1) { + scrollRectToVisible(rect); + } + else { + final Rectangle editorRect = getCellRect(row + 1, 0, false); + if(!rect.isEmpty() && !editorRect.isEmpty()) { + final int height = (int)(rect.getHeight() + editorRect.getHeight()); + final Rectangle visibleRect = new Rectangle((int)rect.getX(), (int)rect.getY(), (int)rect.getWidth(), height); + scrollRectToVisible(visibleRect); + } + } + } + public void showEditor(@NotNull ArrangementMatchingRuleEditor editor, int rowToEdit) { if (myEditorRow == rowToEdit + 1) { return; diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java index fe36724293f4..5bbba9eb8a7c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/util/ArrangementListRowDecorator.java @@ -214,6 +214,7 @@ public class ArrangementListRowDecorator extends JPanel implements ArrangementUi int row = myControl.getRowByRenderer(this); if (row >= 0) { myControl.showEditor(row); + myControl.scrollRowToVisible(row); myBeingEdited = true; } } From dcbad154a9cdb3d867a05b6194feb5e7494b7a61 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 30 Sep 2014 14:35:17 +0400 Subject: [PATCH 70/78] IDEA-129688 Android Studio/IntelliJ - Quick Doc shown on Menu Click --- .../QuickDocOnMouseOverManager.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java index 0cd18020ad54..6156dd99be0c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java @@ -50,7 +50,7 @@ import java.util.Map; */ public class QuickDocOnMouseOverManager { - @NotNull private final EditorMouseMotionListener myMouseListener = new MyEditorMouseListener(); + @NotNull private final MyEditorMouseListener myMouseListener = new MyEditorMouseListener(); @NotNull private final VisibleAreaListener myVisibleAreaListener = new MyVisibleAreaListener(); @NotNull private final CaretListener myCaretListener = new MyCaretListener(); @NotNull private final DocumentListener myDocumentListener = new MyDocumentListener(); @@ -117,6 +117,7 @@ public class QuickDocOnMouseOverManager { } private void registerListeners(@NotNull Editor editor) { + editor.addEditorMouseListener(myMouseListener); editor.addEditorMouseMotionListener(myMouseListener); editor.getScrollingModel().addVisibleAreaListener(myVisibleAreaListener); editor.getCaretModel().addCaretListener(myCaretListener); @@ -128,6 +129,7 @@ public class QuickDocOnMouseOverManager { } private void unRegisterListeners(@NotNull Editor editor) { + editor.removeEditorMouseListener(myMouseListener); editor.removeEditorMouseMotionListener(myMouseListener); editor.getScrollingModel().removeVisibleAreaListener(myVisibleAreaListener); editor.getCaretModel().removeCaretListener(myCaretListener); @@ -137,6 +139,10 @@ public class QuickDocOnMouseOverManager { document.removeDocumentListener(myDocumentListener); } } + + private void processMouseExited() { + myDelayedQuickDocInfo = null; + } private void processMouseMove(@NotNull EditorMouseEvent e) { if (!myApplicationActive || e.getArea() != EditorMouseEventArea.EDITING_AREA) { @@ -335,12 +341,19 @@ public class QuickDocOnMouseOverManager { } } - private class MyEditorMouseListener extends EditorMouseMotionAdapter { + private class MyEditorMouseListener extends EditorMouseAdapter implements EditorMouseMotionListener { + @Override + public void mouseExited(EditorMouseEvent e) { + processMouseExited(); + } @Override public void mouseMoved(EditorMouseEvent e) { processMouseMove(e); } + + @Override + public void mouseDragged(EditorMouseEvent e) {} } private class MyVisibleAreaListener implements VisibleAreaListener { From 2f62139ce68d67b0ddb431dc790825f3283c2524 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 30 Sep 2014 13:03:11 +0200 Subject: [PATCH 71/78] com.jetbrains.plugins.ini4idea added for the list of checked plugins --- platform/platform-resources/src/checkedPlugins.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-resources/src/checkedPlugins.txt b/platform/platform-resources/src/checkedPlugins.txt index 09653e9cdb5a..0d954d91cf4d 100644 --- a/platform/platform-resources/src/checkedPlugins.txt +++ b/platform/platform-resources/src/checkedPlugins.txt @@ -13,4 +13,5 @@ SBT JSTestDriver Plugin com.jetbrains.chronon AngularJS -org.jetbrains.plugins.vagrant \ No newline at end of file +org.jetbrains.plugins.vagrant +com.jetbrains.plugins.ini4idea \ No newline at end of file From 7578b469d48a15fda5d43c5d16c49b9579b589ed Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 30 Sep 2014 15:21:17 +0400 Subject: [PATCH 72/78] get rid of deprecated usages (EnvironmentVariablesComponent.inlineParentOccurrences()) --- python/src/com/jetbrains/python/run/ProcessRunner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/run/ProcessRunner.java b/python/src/com/jetbrains/python/run/ProcessRunner.java index 7a71cc470929..b08739f56d9c 100644 --- a/python/src/com/jetbrains/python/run/ProcessRunner.java +++ b/python/src/com/jetbrains/python/run/ProcessRunner.java @@ -16,7 +16,6 @@ package com.jetbrains.python.run; import com.intellij.execution.*; -import com.intellij.execution.configuration.EnvironmentVariablesComponent; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.ColoredProcessHandler; import com.intellij.openapi.project.Project; @@ -24,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import com.intellij.util.EnvironmentUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -149,7 +149,7 @@ public class ProcessRunner { env.putAll(userDefinedEnv); } //Inline parent env variables occurrences - EnvironmentVariablesComponent.inlineParentOccurrences(env); + EnvironmentUtil.inlineParentOccurrences(env); return cmdLine; } From 0582c58a512c432108d2d3effab74f40a2c76721 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 30 Sep 2014 13:28:42 +0200 Subject: [PATCH 73/78] revert 5de0503b1b148560b9be960581f4920b5a4922bb because renameTo is slow for Windows (DEA-130573) (8.1 ?) and later fact affects rebuild performance significantly --- .../com/intellij/psi/stubs/StubIndexImpl.java | 4 ++-- .../util/indexing/FileBasedIndexImpl.java | 10 +++++----- .../intellij/util/indexing/IndexingStamp.java | 2 +- .../intellij/openapi/util/io/FileUtil.java | 19 +++++++------------ 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java index ffc7de7c9b12..99b5d861cf5e 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java @@ -130,7 +130,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe if (needRebuild) { LOG.info("Version has changed for stub index " + extension.getKey() + ". The index will be rebuilt."); } - FileUtil.delete(indexRootDir); + FileUtil.deleteWithRenaming(indexRootDir); IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices } @@ -164,7 +164,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe private static void onExceptionInstantiatingIndex(int version, File versionFile, File indexRootDir, Exception e) throws IOException { LOG.info(e); - FileUtil.delete(indexRootDir); + FileUtil.deleteWithRenaming(indexRootDir); IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 019b3172817f..d90c2debd02d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -380,9 +380,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { LOG.info("Version has changed for index " + name + ". The index will be rebuilt."); } if (extension.hasSnapshotMapping() && (isCurrentVersionCorrupted || versionChanged)) { - FileUtil.delete(IndexInfrastructure.getPersistentIndexRootDir(name)); + FileUtil.deleteWithRenaming(IndexInfrastructure.getPersistentIndexRootDir(name)); } - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + FileUtil.deleteWithRenaming(IndexInfrastructure.getIndexRootDir(name)); IndexingStamp.rewriteVersion(versionFile, version); } @@ -458,10 +458,10 @@ public class FileBasedIndexImpl extends FileBasedIndex { catch (Exception ignored) { } - FileUtil.delete(IndexInfrastructure.getIndexRootDir(name)); + FileUtil.deleteWithRenaming(IndexInfrastructure.getIndexRootDir(name)); if (extension.hasSnapshotMapping() && (!contentHashesEnumeratorOk || instantiatedStorage)) { - FileUtil.delete(IndexInfrastructure.getPersistentIndexRootDir(name)); + FileUtil.deleteWithRenaming(IndexInfrastructure.getPersistentIndexRootDir(name)); // todo there is possibility of corruption of storage and content hashes } IndexingStamp.rewriteVersion(versionFile, version); } @@ -1564,7 +1564,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { indicesToDrop.remove(key.toString()); } for (String s : indicesToDrop) { - FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s))); + FileUtil.deleteWithRenaming(IndexInfrastructure.getIndexRootDir(ID.create(s))); } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index 5ef1379eaaf4..1e8f43edf062 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -68,7 +68,7 @@ public class IndexingStamp { public static synchronized void rewriteVersion(@NotNull final File file, final int version) throws IOException { final long prevLastModifiedValue = file.lastModified(); if (file.exists()) { - FileUtil.delete(file); + FileUtil.deleteWithRenaming(file); } file.getParentFile().mkdirs(); final DataOutputStream os = FileUtilRt.doIOOperation(new FileUtilRt.RepeatableIOOperation() { diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index bc41f70e933a..4324deee35d4 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -415,17 +415,6 @@ public class FileUtil extends FileUtilRt { } public static boolean delete(@NotNull File file) { - if (SystemInfo.isWindows) { - File tempFile = findSequentNonexistentFile(file.getParentFile(), file.getName(), ""); - if (file.renameTo(tempFile)) { - file = tempFile; - } - } - - return doDelete(file); - } - - private static boolean doDelete(File file) { FileAttributes attributes = FileSystemUtil.getAttributes(file); if (attributes == null) return true; @@ -433,7 +422,7 @@ public class FileUtil extends FileUtilRt { File[] files = file.listFiles(); if (files != null) { for (File child : files) { - if (!doDelete(child)) return false; + if (!delete(child)) return false; } } } @@ -1539,4 +1528,10 @@ public class FileUtil extends FileUtilRt { public static boolean isRootPath(@NotNull String path) { return path.equals("/") || path.matches("[a-zA-Z]:[/\\\\]"); } + + public static boolean deleteWithRenaming(File file) { + File tempFileNameForDeletion = findSequentNonexistentFile(file.getParentFile(), file.getName(), ""); + boolean success = file.renameTo(tempFileNameForDeletion); + return delete(success ? tempFileNameForDeletion:file); + } } From 3ebe32f01cda3fd8560ce6906e35c045bc29479c Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 30 Sep 2014 16:22:14 +0400 Subject: [PATCH 74/78] IDEA-130422 Resize "Project Structure" goes crazy --- .../ui/impl/DialogWrapperPeerImpl.java | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java index ff3977cf4be8..29cbe53511a6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/DialogWrapperPeerImpl.java @@ -547,7 +547,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra private final ActionCallback myFocusedCallback; private final ActionCallback myTypeAheadDone; private final ActionCallback myTypeAheadCallback; - private MyComponentListener myComponentListener; public MyDialog(Window owner, DialogWrapper dialogWrapper, @@ -579,9 +578,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); myWindowListener = new MyWindowListener(); addWindowListener(myWindowListener); - - myComponentListener = new MyComponentListener(); - addComponentListener(myComponentListener); } @Override @@ -852,11 +848,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra myWindowListener = null; } - if (myComponentListener != null) { - removeComponentListener(myComponentListener); - myComponentListener = null; - } - if (myFocusTrackback != null && !(myFocusTrackback.isSheduledForRestore() || myFocusTrackback.isWillBeSheduledForRestore())) { myFocusTrackback.dispose(); myFocusTrackback = null; @@ -1035,20 +1026,12 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra } } - private class MyComponentListener extends ComponentAdapter { - @Override - @SuppressWarnings({"RefusedBequest"}) - public void componentResized(ComponentEvent e) { - if (getDialogWrapper().isAutoAdjustable()) { - UIUtil.adjustWindowToMinimumSize(getWindow()); - } - } - } - private class DialogRootPane extends JRootPane implements DataProvider { private final boolean myGlassPaneIsSet; + private Dimension myLastMinimumSize; + private DialogRootPane() { setGlassPane(new IdeGlassPaneImpl(this)); myGlassPaneIsSet = true; @@ -1062,6 +1045,31 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra return p; } + @Override + public void validate() { + super.validate(); + DialogWrapper wrapper = myDialogWrapper.get(); + if (wrapper != null && wrapper.isAutoAdjustable()) { + Window window = wrapper.getWindow(); + if (window != null) { + Dimension size = getMinimumSize(); + if (!(size == null ? myLastMinimumSize == null : size.equals(myLastMinimumSize))) { + // update window minimum size only if root pane minimum size is changed + if (size == null) { + myLastMinimumSize = null; + } + else { + myLastMinimumSize = new Dimension(size); + Insets insets = window.getInsets(); + size.width += insets.left + insets.right; + size.height += insets.top + insets.bottom; + } + window.setMinimumSize(size); + } + } + } + } + @Override public void setGlassPane(final Component glass) { if (myGlassPaneIsSet) { From 5139a2c3e9d28b3911658be96af2d9844383f9a1 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 29 Sep 2014 18:12:03 +0400 Subject: [PATCH 75/78] [push] notify about selection change after loading finishes only if the node state was actually changed. Otherwise it might deselect the previously selected node in the model. --- .../dvcs-impl/src/com/intellij/dvcs/push/PushController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java index b95ed788cbb1..c434ff41fd2c 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -320,8 +320,9 @@ public class PushController implements Disposable { node.stopLoading(); if (shouldBeSelected) { // never remove selection; initially all checkboxes are not selected node.setChecked(true); + model.setSelected(true); } - node.fireOnSelectionChange(shouldBeSelected); + myDialog.updateButtons(); } }); } From b5302ba1a299d32c2aaff82defea73252d05df3e Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 29 Sep 2014 19:37:43 +0400 Subject: [PATCH 76/78] [push] Initially there is no loading going on (in general) --- .../dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java index b75ce5079558..29a021113887 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicReference; public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, Comparable { @NotNull protected final LoadingIcon myLoadingIcon; - @NotNull protected final AtomicBoolean myLoading = new AtomicBoolean(true); + @NotNull protected final AtomicBoolean myLoading = new AtomicBoolean(); @NotNull private final RepositoryWithBranchPanel myRepositoryPanel; @Nullable private Future> myFuture; From 23109d5a0e85589283750fc180038651f27b33ff Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 30 Sep 2014 15:08:58 +0400 Subject: [PATCH 77/78] [push] IDEA-130258 Better show diff for selection * Reverse sort selected rows * Support multiple repository nodes selection, as well as mixed repository node + commit node selection. --- .../com/intellij/dvcs/push/ui/PushLog.java | 121 +++++++++++------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index d875103c29d6..78a90f21992a 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -31,8 +31,8 @@ import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.ScrollPaneFactory; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.tree.TreeUtil; -import com.intellij.vcs.log.VcsFullCommitDetails; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -44,10 +44,8 @@ import javax.swing.tree.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EventObject; +import java.util.*; +import java.util.List; public class PushLog extends JPanel implements TypeSafeDataProvider { @@ -167,40 +165,63 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { } private void updateChangesView() { - TreePath[] nodes = myTree.getSelectionPaths(); - if (nodes != null) { - ArrayList changes = new ArrayList(); - for (TreePath path : nodes) { - if (path.getLastPathComponent() instanceof CommitNode) { - CommitNode commitDetailsNode = (CommitNode)path.getLastPathComponent(); - changes.addAll(commitDetailsNode.getUserObject().getChanges()); - } - else if (path.getLastPathComponent() instanceof RepositoryNode) { - changes.addAll(collectAllChanges((RepositoryNode)path.getLastPathComponent())); - } - } + int[] rows = myTree.getSelectionRows(); + if (rows.length != 0) { myChangesBrowser.getViewer().setEmptyText("No differences"); - myChangesBrowser.setChangesToDisplay(CommittedChangesTreeBrowser.zipChanges(changes)); - return; + myChangesBrowser.setChangesToDisplay(collectAllChanges(rows)); + } + else { + setDefaultEmptyText(); + myChangesBrowser.setChangesToDisplay(Collections.emptyList()); } - setDefaultEmptyText(); - myChangesBrowser.setChangesToDisplay(Collections.emptyList()); } @NotNull - private static Collection collectAllChanges(@NotNull RepositoryNode rootNode) { - ArrayList changes = new ArrayList(); - if (rootNode.getChildCount() <= 0) return changes; - for (DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)rootNode.getFirstChild(); - childNode != null; - childNode = (DefaultMutableTreeNode)rootNode.getChildAfter(childNode)) { - if (childNode instanceof CommitNode) { - changes.addAll(((CommitNode)childNode).getUserObject().getChanges()); + private List collectAllChanges(@NotNull int[] selectedRows) { + List selectedNodes = getNodesForRows(getSortedRows(selectedRows)); + List commitNodes = collectSelectedCommitNodes(selectedNodes); + return CommittedChangesTreeBrowser.zipChanges(collectChanges(commitNodes)); + } + + @NotNull + private static List collectSelectedCommitNodes(@NotNull List selectedNodes) { + List nodes = ContainerUtil.newArrayList(); + for (DefaultMutableTreeNode node : selectedNodes) { + if (node instanceof RepositoryNode) { + nodes.addAll(getChildNodes((RepositoryNode)node)); + } + else if (node instanceof CommitNode && !nodes.contains(node)) { + nodes.add((CommitNode)node); } } + return nodes; + } + + @NotNull + private static List collectChanges(@NotNull List commitNodes) { + List changes = ContainerUtil.newArrayList(); + for (CommitNode node : commitNodes) { + changes.addAll(node.getUserObject().getChanges()); + } return changes; } + @NotNull + private static List getChildNodes(@NotNull RepositoryNode node) { + List nodes = ContainerUtil.newArrayList(); + if (node.getChildCount() < 1) { + return nodes; + } + for (DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)node.getFirstChild(); + childNode != null; + childNode = (DefaultMutableTreeNode)node.getChildAfter(childNode)) { + if (childNode instanceof CommitNode) { + nodes.add(0, (CommitNode)childNode); + } + } + return nodes; + } + private void setDefaultEmptyText() { myChangesBrowser.getViewer().setEmptyText("No commits selected"); } @@ -209,27 +230,37 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { @Override public void calcData(DataKey key, DataSink sink) { if (VcsDataKeys.CHANGES.equals(key)) { - DefaultMutableTreeNode[] selectedNodes = myTree.getSelectedNodes(DefaultMutableTreeNode.class, null); - if (selectedNodes.length == 0) { - return; - } - DefaultMutableTreeNode node = selectedNodes[0]; - Object object = node.getUserObject(); - - Collection changes = null; - if (object instanceof VcsFullCommitDetails) { - changes = ((VcsFullCommitDetails)object).getChanges(); - } - else if (node instanceof RepositoryNode) { - changes = collectAllChanges((RepositoryNode)node); - } - - if (changes != null) { + int[] rows = myTree.getSelectionRows(); + if (rows.length != 0) { + Collection changes = collectAllChanges(rows); sink.put(key, ArrayUtil.toObjectArray(changes, Change.class)); } } } + @NotNull + private static List getSortedRows(@NotNull int[] rows) { + List sorted = ContainerUtil.newArrayList(); + for (int row : rows) { + sorted.add(row); + } + Collections.sort(sorted, Collections.reverseOrder()); + return sorted; + } + + @NotNull + private List getNodesForRows(@NotNull List rows) { + List nodes = ContainerUtil.newArrayList(); + for (Integer row : rows) { + TreePath path = myTree.getPathForRow(row); + Object pathComponent = path == null ? null : path.getLastPathComponent(); + if (pathComponent instanceof DefaultMutableTreeNode) { + nodes.add((DefaultMutableTreeNode)pathComponent); + } + } + return nodes; + } + @Override protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (e.getKeyCode() == KeyEvent.VK_ENTER && e.getModifiers() == 0 && pressed) { From 24ae2526dba54e4e9b4759cd79fae97d8c4022f5 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 30 Sep 2014 16:21:57 +0400 Subject: [PATCH 78/78] [git] fix parameter case --- plugins/git4idea/src/git4idea/push/GitPushOperation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPushOperation.java b/plugins/git4idea/src/git4idea/push/GitPushOperation.java index 634ded46c792..6d862689556f 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushOperation.java +++ b/plugins/git4idea/src/git4idea/push/GitPushOperation.java @@ -357,9 +357,9 @@ public class GitPushOperation { }); } - private void savePushUpdateSettings(@NotNull PushUpdateSettings PushUpdateSettings) { - UpdateMethod updateMethod = PushUpdateSettings.getUpdateMethod(); - myPushSettings.setUpdateAllRoots(PushUpdateSettings.shouldUpdateAllRoots()); + private void savePushUpdateSettings(@NotNull PushUpdateSettings settings) { + UpdateMethod updateMethod = settings.getUpdateMethod(); + myPushSettings.setUpdateAllRoots(settings.shouldUpdateAllRoots()); myPushSettings.setUpdateMethod(updateMethod); }