diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index adbc722f6d10..376561535a1e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -62,7 +62,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring { ); private ResolveSnapshotProvider.ResolveSnapshot mySnapshot; private TextRange mySelectedRange; - private Language myLanguage; + protected Language myLanguage; public VariableInplaceRenamer(@NotNull PsiNamedElement elementToRename, Editor editor) { this(elementToRename, editor, elementToRename.getProject()); diff --git a/platform/platform-impl/src/com/intellij/ui/mac/JDK7WindowReorderingWorkaround.java b/platform/platform-impl/src/com/intellij/ui/mac/JDK7WindowReorderingWorkaround.java new file mode 100644 index 000000000000..267e0e70b73f --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/mac/JDK7WindowReorderingWorkaround.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2013 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.ui.mac; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.mac.foundation.Foundation; +import com.intellij.ui.mac.foundation.ID; +import com.sun.jna.Callback; +import com.sun.jna.Pointer; + +import java.util.concurrent.atomic.AtomicInteger; + +import static com.intellij.ui.mac.foundation.Foundation.invoke; + +/** + * @author Denis Fokin + */ +public class JDK7WindowReorderingWorkaround { + + private static AtomicInteger requestorCount = new AtomicInteger(); + + private static final Callback windowDidBecomeMainCallback = new Callback() { + @SuppressWarnings("UnusedDeclaration") // this is a native up-call + public void callback(ID self, + ID nsNotification) + { + if (requestorCount.intValue() == 0) { + invoke(self, "oldWindowDidBecomeMain:", nsNotification); + } + } + }; + + static { + if (SystemInfo.isJavaVersionAtLeast("1.7")) { + ID awtWindow = Foundation.getObjcClass("AWTWindow"); + + Pointer windowWillEnterFullScreenMethod = Foundation.createSelector("windowDidBecomeMain:"); + ID originalWindowWillEnterFullScreen = Foundation.class_replaceMethod(awtWindow, windowWillEnterFullScreenMethod, + windowDidBecomeMainCallback, "v@::@"); + + Foundation.addMethodByID(awtWindow, Foundation.createSelector("oldWindowDidBecomeMain:"), + originalWindowWillEnterFullScreen, "v@::@"); + } + } + + static void disableReordering() { + if (SystemInfo.isJavaVersionAtLeast("1.7")) { + requestorCount.incrementAndGet(); + } + } + + static void enableReordering () { + if (SystemInfo.isJavaVersionAtLeast("1.7")) { + requestorCount.decrementAndGet(); + } + } + +} diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java index 80c214e8eb23..76bf9b32586c 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java @@ -137,6 +137,7 @@ public class MacFileChooserDialogImpl implements PathChooserDialog { finally { Foundation.cfRelease(self); Foundation.cfRelease(contextInfo); + JDK7WindowReorderingWorkaround.enableReordering(); } } }; @@ -323,6 +324,7 @@ public class MacFileChooserDialogImpl implements PathChooserDialog { ourImplMap.put(delegate, impl); final ID select = toSelect == null ? null : Foundation.nsString(toSelect); + JDK7WindowReorderingWorkaround.disableReordering(); invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:", Foundation.createSelector("showOpenPanel:"), select, false); } diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java index db65c46fb15d..a4e5dce7ee0e 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacMessagesImpl.java @@ -36,7 +36,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -72,6 +71,7 @@ public class MacMessagesImpl extends MacMessages { resultsFromDocumentRoot.put(documentRoot, new MessageResult(returnCode.intValue(), suppressState.intValue() == 1)); queuesFromDocumentRoot.get(windowFromId.get(contextInfo.longValue())).runFromQueue(); } + JDK7WindowReorderingWorkaround.enableReordering(); cfRelease(self); } }; @@ -203,6 +203,7 @@ public class MacMessagesImpl extends MacMessages { private MacMessagesImpl() {} private static final Callback windowDidBecomeMainCallback = new Callback() { + @SuppressWarnings("UnusedDeclaration") // this is a native up-call public void callback(ID self, ID nsNotification) { @@ -357,6 +358,7 @@ public class MacMessagesImpl extends MacMessages { private static void startModal(final Window w, ID windowId) { long windowPtr = windowId.longValue(); synchronized (lock) { + JDK7WindowReorderingWorkaround.disableReordering(); windowFromId.put(windowPtr, w); if (blockedDocumentRoots.keySet().contains(w)) { blockedDocumentRoots.put(w, blockedDocumentRoots.get(w) + 1); @@ -566,7 +568,7 @@ public class MacMessagesImpl extends MacMessages { final Window documentRoot = getDocumentRootFromWindow(foremostWindow); - final ID nativeFocusedWindow = windowIdFromWindow(foremostWindow); + final ID nativeFocusedWindow = MacUtil.findWindowFromJavaWindow(foremostWindow); paramsWrapper.setNativeWindow(nativeFocusedWindow); @@ -591,54 +593,10 @@ public class MacMessagesImpl extends MacMessages { return documentRoot; } - private static ID windowIdFromWindow (Window w) { - - ID windowId = null; - - if (SystemInfo.isJavaVersionAtLeast("1.7") && Registry.is("skip.untitled.windows.for.mac.messages")) { - try { - Class cWindowPeerClass = w.getPeer().getClass(); - Method getPlatformWindowMethod = cWindowPeerClass.getDeclaredMethod("getPlatformWindow"); - Object cPlatformWindow = getPlatformWindowMethod.invoke(w.getPeer()); - Class cPlatformWindowClass = cPlatformWindow.getClass(); - Method getNSWindowPtrMethod = cPlatformWindowClass.getDeclaredMethod("getNSWindowPtr"); - windowId = new ID((Long)getNSWindowPtrMethod.invoke(cPlatformWindow)); - } - catch (NoSuchMethodException e) { - LOG.debug(e); - } - catch (InvocationTargetException e) { - LOG.debug(e); - } - catch (IllegalAccessException e) { - LOG.debug(e); - } - - } else { - String foremostWindowTitle = getWindowTitle(w); - windowId = MacUtil.findWindowForTitle(foremostWindowTitle); - } - - return windowId; - - } - private static int convertReturnCodeFromNativeMessageDialog(int result) { return result - 1000; } - private static String getWindowTitle(Window documentRoot) { - String windowTitle; - if (documentRoot instanceof Frame) { - windowTitle = ((Frame)documentRoot).getTitle(); - } else if (documentRoot instanceof Dialog) { - windowTitle = ((Dialog)documentRoot).getTitle(); - } else { - throw new RuntimeException("The window is not a frame and not a dialog!"); - } - return windowTitle; - } - @Messages.YesNoCancelResult private static int convertReturnCodeFromNativeAlertDialog(int returnCode, String alternateText) { // DEFAULT = 1 @@ -744,8 +702,8 @@ public class MacMessagesImpl extends MacMessages { } //Actually can, but not in this implementation. If you know a reasonable scenario, please ask Denis Fokin for the improvement. - LOG.assertTrue(getWindowTitle(_window) != null, "A window without a title should not be used for showing MacMessages"); - while (_window != null && getWindowTitle(_window) == null) { + LOG.assertTrue(MacUtil.getWindowTitle(_window) != null, "A window without a title should not be used for showing MacMessages"); + while (_window != null && MacUtil.getWindowTitle(_window) == null) { _window = _window.getOwner(); //At least our frame should have a title } diff --git a/platform/util/src/com/intellij/execution/process/BaseOSProcessHandler.java b/platform/util/src/com/intellij/execution/process/BaseOSProcessHandler.java index a44d8f76f04d..463708e1b9af 100644 --- a/platform/util/src/com/intellij/execution/process/BaseOSProcessHandler.java +++ b/platform/util/src/com/intellij/execution/process/BaseOSProcessHandler.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Consumer; +import com.intellij.util.io.BaseDataReader; import com.intellij.util.io.BaseOutputReader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,7 +29,7 @@ import java.io.*; import java.nio.charset.Charset; import java.util.concurrent.*; -import static com.intellij.util.io.BaseOutputReader.AdaptiveSleepingPolicy; +import static com.intellij.util.io.BaseDataReader.AdaptiveSleepingPolicy; public class BaseOSProcessHandler extends ProcessHandler implements TaskExecutor { private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.OSProcessHandlerBase"); @@ -82,13 +83,10 @@ public class BaseOSProcessHandler extends ProcessHandler implements TaskExecutor @Override public void startNotified(final ProcessEvent event) { try { - BaseOutputReader.SleepingPolicy sleepingPolicy = - useAdaptiveSleepingPolicyWhenReadingOutput() ? new AdaptiveSleepingPolicy() : BaseOutputReader.SleepingPolicy.SIMPLE; - final BaseOutputReader stdoutReader = new SimpleOutputReader(createProcessOutReader(), ProcessOutputTypes.STDOUT, sleepingPolicy); - final BaseOutputReader stderrReader = processHasSeparateErrorStream() - ? new SimpleOutputReader(createProcessErrReader(), ProcessOutputTypes.STDERR, - sleepingPolicy) - : null; + BaseDataReader.SleepingPolicy sleepingPolicy = + useAdaptiveSleepingPolicyWhenReadingOutput() ? new AdaptiveSleepingPolicy() : BaseDataReader.SleepingPolicy.SIMPLE; + final BaseDataReader stdoutReader = createOutputDataReader(sleepingPolicy); + final BaseDataReader stderrReader = processHasSeparateErrorStream() ? createErrorDataReader(sleepingPolicy) : null; myWaitFor.setTerminationCallback(new Consumer() { @Override @@ -120,6 +118,17 @@ public class BaseOSProcessHandler extends ProcessHandler implements TaskExecutor super.startNotify(); } + @NotNull + protected BaseDataReader createErrorDataReader(BaseDataReader.SleepingPolicy sleepingPolicy) { + return new SimpleOutputReader(createProcessErrReader(), ProcessOutputTypes.STDERR, + sleepingPolicy); + } + + @NotNull + protected BaseDataReader createOutputDataReader(BaseDataReader.SleepingPolicy sleepingPolicy) { + return new SimpleOutputReader(createProcessOutReader(), ProcessOutputTypes.STDOUT, sleepingPolicy); + } + protected void onOSProcessTerminated(final int exitCode) { notifyProcessTerminated(exitCode); } diff --git a/platform/util/src/com/intellij/ui/mac/foundation/MacUtil.java b/platform/util/src/com/intellij/ui/mac/foundation/MacUtil.java index f2afa0392f37..7a0bda72f406 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/MacUtil.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/MacUtil.java @@ -16,9 +16,11 @@ package com.intellij.ui.mac.foundation; import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,6 +29,8 @@ import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.event.AWTEventListener; import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import static com.intellij.ui.mac.foundation.Foundation.invoke; import static com.intellij.ui.mac.foundation.Foundation.toStringViaUTF8; @@ -35,6 +39,7 @@ import static com.intellij.ui.mac.foundation.Foundation.toStringViaUTF8; * @author pegov */ public class MacUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.mac.foundation.MacUtil"); public static final String MAC_NATIVE_WINDOW_SHOWING = "MAC_NATIVE_WINDOW_SHOWING"; private MacUtil() { @@ -72,7 +77,7 @@ public class MacUtil { return focusedWindow; } - + public static synchronized void startModal(JComponent component, String key) { try { if (SwingUtilities.isEventDispatchThread()) { @@ -91,7 +96,7 @@ public class MacUtil { ((MenuComponent)source).dispatchEvent(event); } else { - System.err.println("Unable to dispatch: " + event); + LOG.debug("Unable to dispatch: " + event); } } } @@ -137,4 +142,47 @@ public class MacUtil { }); Toolkit.getDefaultToolkit().addAWTEventListener(listener, AWTEvent.KEY_EVENT_MASK); } + + @SuppressWarnings("deprecation") + public static ID findWindowFromJavaWindow(final Window w) { + ID windowId = null; + if (SystemInfo.isJavaVersionAtLeast("1.7") && Registry.is("skip.untitled.windows.for.mac.messages")) { + try { + //noinspection deprecation + Class cWindowPeerClass = w.getPeer().getClass(); + Method getPlatformWindowMethod = cWindowPeerClass.getDeclaredMethod("getPlatformWindow"); + Object cPlatformWindow = getPlatformWindowMethod.invoke(w.getPeer()); + Class cPlatformWindowClass = cPlatformWindow.getClass(); + Method getNSWindowPtrMethod = cPlatformWindowClass.getDeclaredMethod("getNSWindowPtr"); + windowId = new ID((Long)getNSWindowPtrMethod.invoke(cPlatformWindow)); + } + catch (NoSuchMethodException e) { + LOG.debug(e); + } + catch (InvocationTargetException e) { + LOG.debug(e); + } + catch (IllegalAccessException e) { + LOG.debug(e); + } + + } else { + String foremostWindowTitle = getWindowTitle(w); + windowId = findWindowForTitle(foremostWindowTitle); + } + return windowId; + } + + + public static String getWindowTitle(Window documentRoot) { + String windowTitle; + if (documentRoot instanceof Frame) { + windowTitle = ((Frame)documentRoot).getTitle(); + } else if (documentRoot instanceof Dialog) { + windowTitle = ((Dialog)documentRoot).getTitle(); + } else { + throw new RuntimeException("The window is not a frame and not a dialog!"); + } + return windowTitle; + } } diff --git a/platform/util/src/com/intellij/util/io/BaseDataReader.java b/platform/util/src/com/intellij/util/io/BaseDataReader.java new file mode 100644 index 000000000000..5b0226667edd --- /dev/null +++ b/platform/util/src/com/intellij/util/io/BaseDataReader.java @@ -0,0 +1,139 @@ +/* + * Copyright 2000-2013 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.util.io; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.TimeoutUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * @author Konstantin Kolosovsky. + */ +public abstract class BaseDataReader { + private static final Logger LOG = Logger.getInstance(BaseDataReader.class); + + protected volatile boolean isStopped = false; + + private Future myFinishedFuture = null; + @NotNull protected final SleepingPolicy mySleepingPolicy; + + public BaseDataReader(SleepingPolicy sleepingPolicy) { + mySleepingPolicy = sleepingPolicy != null ? sleepingPolicy: SleepingPolicy.SIMPLE; + } + + protected void start() { + if (myFinishedFuture == null) { + myFinishedFuture = executeOnPooledThread(new Runnable() { + @Override + public void run() { + doRun(); + } + }); + } + } + + protected abstract Future executeOnPooledThread(Runnable runnable); + + public interface SleepingPolicy { + int sleepTimeWhenWasActive = 1; + int sleepTimeWhenIdle = 5; + + SleepingPolicy SIMPLE = new SleepingPolicy() { + @Override + public int getTimeToSleep(boolean wasActive) { + return wasActive ? sleepTimeWhenWasActive : sleepTimeWhenIdle; + } + }; + + int getTimeToSleep(boolean wasActive); + } + + public static class AdaptiveSleepingPolicy implements SleepingPolicy { + private static final int maxSleepTimeWhenIdle = 200; + private static final int maxIterationsWithCurrentSleepTime = 50; + + private volatile int myIterationsWithCurrentTime; + private volatile int myCurrentSleepTime = sleepTimeWhenIdle; + + @Override + public int getTimeToSleep(boolean wasActive) { + int currentSleepTime = myCurrentSleepTime; // volatile read + if (wasActive) currentSleepTime = sleepTimeWhenWasActive; + else if (currentSleepTime == sleepTimeWhenWasActive) { + currentSleepTime = sleepTimeWhenIdle; + myIterationsWithCurrentTime = 0; + } + else { + int iterationsWithCurrentTime = ++myIterationsWithCurrentTime; + if (iterationsWithCurrentTime >= maxIterationsWithCurrentSleepTime) { + myIterationsWithCurrentTime = 0; + currentSleepTime = Math.min(2* currentSleepTime, maxSleepTimeWhenIdle); + } + } + + myCurrentSleepTime = currentSleepTime; // volatile write + return currentSleepTime; + } + } + + protected void doRun() { + try { + while (true) { + boolean read = readAvailable(); + + if (isStopped) { + break; + } + + TimeoutUtil.sleep(mySleepingPolicy.getTimeToSleep(read)); + } + } + catch (IOException e) { + LOG.info(e); + } + catch (Exception e) { + LOG.error(e); + } + finally { + try { + close(); + } + catch (IOException e) { + LOG.error("Can't close stream", e); + } + } + } + + protected abstract boolean readAvailable() throws IOException; + protected abstract void close() throws IOException; + + public void stop() { + isStopped = true; + } + + public void waitFor() throws InterruptedException { + try { + myFinishedFuture.get(); + } + catch (ExecutionException e) { + LOG.error(e); + } + } +} diff --git a/platform/util/src/com/intellij/util/io/BaseOutputReader.java b/platform/util/src/com/intellij/util/io/BaseOutputReader.java index ba1e187b8363..d6684414110c 100644 --- a/platform/util/src/com/intellij/util/io/BaseOutputReader.java +++ b/platform/util/src/com/intellij/util/io/BaseOutputReader.java @@ -15,121 +15,29 @@ */ package com.intellij.util.io; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.util.TimeoutUtil; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.Reader; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; /** * @author traff */ -public abstract class BaseOutputReader { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.BaseOutputReader"); +public abstract class BaseOutputReader extends BaseDataReader { protected final Reader myReader; - protected volatile boolean isStopped = false; private final char[] myBuffer = new char[8192]; private final StringBuilder myTextBuffer = new StringBuilder(); private boolean skipLF = false; - private Future myFinishedFuture = null; - @NotNull protected final SleepingPolicy mySleepingPolicy; - public BaseOutputReader(@NotNull Reader reader) { this(reader, null); } public BaseOutputReader(@NotNull Reader reader, SleepingPolicy sleepingPolicy) { + super(sleepingPolicy); myReader = reader; - mySleepingPolicy = sleepingPolicy != null ? sleepingPolicy: SleepingPolicy.SIMPLE; - } - - protected void start() { - if (myFinishedFuture == null) { - myFinishedFuture = executeOnPooledThread(new Runnable() { - @Override - public void run() { - doRun(); - } - }); - } - } - - protected abstract Future executeOnPooledThread(Runnable runnable); - - public interface SleepingPolicy { - int sleepTimeWhenWasActive = 1; - int sleepTimeWhenIdle = 5; - - SleepingPolicy SIMPLE = new SleepingPolicy() { - @Override - public int getTimeToSleep(boolean wasActive) { - return wasActive ? sleepTimeWhenWasActive : sleepTimeWhenIdle; - } - }; - - int getTimeToSleep(boolean wasActive); - } - - public static class AdaptiveSleepingPolicy implements SleepingPolicy { - private static final int maxSleepTimeWhenIdle = 200; - private static final int maxIterationsWithCurrentSleepTime = 50; - - private volatile int myIterationsWithCurrentTime; - private volatile int myCurrentSleepTime = sleepTimeWhenIdle; - - @Override - public int getTimeToSleep(boolean wasActive) { - int currentSleepTime = myCurrentSleepTime; // volatile read - if (wasActive) currentSleepTime = sleepTimeWhenWasActive; - else if (currentSleepTime == sleepTimeWhenWasActive) { - currentSleepTime = sleepTimeWhenIdle; - myIterationsWithCurrentTime = 0; - } - else { - int iterationsWithCurrentTime = ++myIterationsWithCurrentTime; - if (iterationsWithCurrentTime >= maxIterationsWithCurrentSleepTime) { - myIterationsWithCurrentTime = 0; - currentSleepTime = Math.min(2* currentSleepTime, maxSleepTimeWhenIdle); - } - } - - myCurrentSleepTime = currentSleepTime; // volatile write - return currentSleepTime; - } - } - - protected void doRun() { - try { - while (true) { - boolean read = readAvailable(); - - if (isStopped) { - break; - } - - TimeoutUtil.sleep(mySleepingPolicy.getTimeToSleep(read)); - } - } - catch (IOException e) { - LOG.info(e); - } - catch (Exception e) { - LOG.error(e); - } - finally { - try { - myReader.close(); - } - catch (IOException e) { - LOG.error("Can't close stream", e); - } - } } /** @@ -176,18 +84,10 @@ public abstract class BaseOutputReader { return read; } + @Override + protected void close() throws IOException { + myReader.close(); + } + protected abstract void onTextAvailable(@NotNull String text); - - public void stop() { - isStopped = true; - } - - public void waitFor() throws InterruptedException { - try { - myFinishedFuture.get(); - } - catch (ExecutionException e) { - LOG.error(e); - } - } } diff --git a/platform/util/src/com/intellij/util/io/BinaryOutputReader.java b/platform/util/src/com/intellij/util/io/BinaryOutputReader.java new file mode 100644 index 000000000000..a80fb50796cd --- /dev/null +++ b/platform/util/src/com/intellij/util/io/BinaryOutputReader.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 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.util.io; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.InputStream; + +/** +* @author Konstantin Kolosovsky. +*/ +public abstract class BinaryOutputReader extends BaseDataReader { + + @NotNull private final InputStream myStream; + @NotNull private final byte[] myBuffer = new byte[8192]; + + public BinaryOutputReader(@NotNull InputStream stream, SleepingPolicy sleepingPolicy) { + super(sleepingPolicy); + myStream = stream; + } + + @Override + protected boolean readAvailable() throws IOException { + byte[] buffer = myBuffer; + + boolean read = false; + while (myStream.available() > 0) { + int n = myStream.read(buffer); + if (n <= 0) break; + read = true; + + onBinaryAvailable(buffer, n); + } + + return read; + } + + protected abstract void onBinaryAvailable(@NotNull byte[] data, int size); + + @Override + protected void close() throws IOException { + myStream.close(); + } +} 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 556691a06c6f..a7580aedd4f8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java @@ -22,13 +22,18 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.EventDispatcher; +import com.intellij.util.io.BaseDataReader; +import com.intellij.util.io.BinaryOutputReader; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.tmatesoft.svn.core.SVNCancelException; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStreamWriter; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -117,7 +122,13 @@ public class CommandExecutor { @NotNull protected OSProcessHandler createProcessHandler() { - return new OSProcessHandler(myProcess, myCommandLine.getCommandLineString()); + return needsBinaryOutput() + ? new BinaryOSProcessHandler(myProcess, myCommandLine.getCommandLineString()) + : new OSProcessHandler(myProcess, myCommandLine.getCommandLineString()); + } + + private boolean needsBinaryOutput() { + return SvnCommandName.cat.equals(myCommand.getName()); } @NotNull @@ -142,6 +153,11 @@ public class CommandExecutor { return outputAdapter.getOutput().getStderr(); } + @Nullable + public ByteArrayOutputStream getBinaryOutput() { + return myHandler instanceof BinaryOSProcessHandler ? ((BinaryOSProcessHandler)myHandler).myBinaryOutput : null; + } + // TODO: Carefully here - do not modify command from threads other than the one started command execution @NotNull public Command getCommand() { @@ -344,4 +360,38 @@ public class CommandExecutor { } } } + + private static class BinaryOSProcessHandler extends OSProcessHandler { + + @NotNull private final ByteArrayOutputStream myBinaryOutput; + + public BinaryOSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) { + super(process, commandLine); + myBinaryOutput = new ByteArrayOutputStream(); + } + + @NotNull + @Override + protected BaseDataReader createOutputDataReader(BaseDataReader.SleepingPolicy sleepingPolicy) { + return new SimpleBinaryOutputReader(myProcess.getInputStream(), sleepingPolicy); + } + + private class SimpleBinaryOutputReader extends BinaryOutputReader { + + public SimpleBinaryOutputReader(@NotNull InputStream stream, SleepingPolicy sleepingPolicy) { + super(stream, sleepingPolicy); + start(); + } + + @Override + protected void onBinaryAvailable(@NotNull byte[] data, int size) { + myBinaryOutput.write(data, 0, size); + } + + @Override + protected Future executeOnPooledThread(Runnable runnable) { + return BinaryOSProcessHandler.this.executeOnPooledThread(runnable); + } + } + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java index 2b1c22ee5c1a..d654253bf426 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/content/CmdContentClient.java @@ -10,6 +10,7 @@ import org.jetbrains.idea.svn.commandLine.*; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; +import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; @@ -22,17 +23,17 @@ public class CmdContentClient extends BaseSvnClient implements ContentClient { public byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision) throws VcsException, FileTooBigRuntimeException { // TODO: rewrite this to provide output as Stream - // TODO: rewrite without conversion from String to byte[] // TODO: Also implement max size constraint like in SvnKitContentClient - // TODO: Could not use export to get content of scheduled for deletion file - use cat command, but write special binary handler + // NOTE: Export could not be used to get content of scheduled for deletion file List parameters = new ArrayList(); CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision); CommandUtil.put(parameters, revision); CommandExecutor command = CommandUtil.execute(myVcs, target, SvnCommandName.cat, parameters, null); - - byte[] bytes = CharsetToolkit.getUtf8Bytes(command.getOutput()); + // TODO: currently binary output will be null for terminal mode - use text output in this case + ByteArrayOutputStream output = command.getBinaryOutput(); + byte[] bytes = output != null ? output.toByteArray() : CharsetToolkit.getUtf8Bytes(command.getOutput()); ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), bytes.length); diff --git a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml index 624d146a0378..ce37b6ba8beb 100644 --- a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml +++ b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml @@ -7,7 +7,8 @@ - + + \ No newline at end of file diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyCommentInjector.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyCommentInjector.java new file mode 100644 index 000000000000..45eb96bfaca0 --- /dev/null +++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyCommentInjector.java @@ -0,0 +1,25 @@ +package com.jetbrains.python.intelliLang; + +import com.intellij.lang.Language; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.codeInsight.PyInjectorBase; +import org.intellij.plugins.intelliLang.inject.InjectedLanguage; +import org.intellij.plugins.intelliLang.inject.InjectorUtils; +import org.intellij.plugins.intelliLang.inject.config.BaseInjection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author vlan + */ +public class PyCommentInjector extends PyInjectorBase { + @Nullable + @Override + public Language getInjectedLanguage(@NotNull PsiElement context) { + final BaseInjection injection = InjectorUtils.findCommentInjection(context, "comment", null); + if (injection != null) { + return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()); + } + return null; + } +} diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java index 43db1f20d814..dee16d27646f 100644 --- a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java +++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java @@ -15,10 +15,13 @@ */ package com.jetbrains.python.intelliLang; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLanguageInjectionHost; import com.jetbrains.python.patterns.PythonPatterns; import com.jetbrains.python.psi.PyElement; import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport; +import org.intellij.plugins.intelliLang.inject.config.BaseInjection; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,4 +54,10 @@ public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport public String getHelpId() { return "reference.settings.language.injection.generic.python"; } + + @Nullable + @Override + public BaseInjection findCommentInjection(@NotNull PsiElement host, @Nullable Ref commentRef) { + return null; + } }