/*
* External Code Formatter Copyright (c) 2007-2009 Esko Luontola, www.orfjackal.net 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 krasa.formatter.plugin;
import static krasa.formatter.plugin.ProxyUtils.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.picocontainer.MutablePicoContainer;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl;
import krasa.formatter.settings.Settings;
/**
* Switches a project's {@link CodeStyleManager} to a eclipse formatter and back.
*
* @author Esko Luontola
* @author Vojtech Krasa
* @since 2.12.2007
*/
public class ProjectCodeStyleInstaller {
private static final String CODE_STYLE_MANAGER_KEY = CodeStyleManager.class.getName();
private static final Logger LOG = Logger.getInstance(ProjectCodeStyleInstaller.class.getName());
@NotNull
private final Project project;
public ProjectCodeStyleInstaller(@NotNull Project project) {
this.project = project;
}
@NotNull
public Project getProject() {
return project;
}
public void changeFormatterTo(@Nullable Settings settings) {
uninstallCodeFormatter();
if (settings != null) {
installCodeFormatter(settings);
}
}
private void installCodeFormatter(@NotNull Settings settings) {
CodeStyleManager manager = CodeStyleManager.getInstance(project);
String canonicalName = manager.getClass().getCanonicalName();
if (!(manager instanceof CodeStyleManagerImpl)) {
throw new RuntimeException("CodeStyleManager conflict, another formatter plugin is probably installed: " + canonicalName);
}
if (Settings.Formatter.ECLIPSE.equals(settings.getFormatter()) && !isMyProxy(manager)) {
EclipseCodeStyleManager overridingObject;
if (compatibleWith_2016_3_API()) {
overridingObject = new EclipseCodeStyleManager_IJ_2016_3(manager, settings);
} else {
overridingObject = new EclipseCodeStyleManager(manager, settings);
}
CodeStyleManager proxy = createProxy((CodeStyleManagerImpl) manager, overridingObject);
registerCodeStyleManager(project, proxy);
}
}
private boolean compatibleWith_2016_3_API() {
Class<?> aClass = null;
try {
aClass = Class.forName("com.intellij.psi.codeStyle.ChangedRangesInfo");
} catch (ClassNotFoundException e) {
}
return aClass != null;
}
private void uninstallCodeFormatter() {
CodeStyleManager delegate = getDelegate(CodeStyleManager.getInstance(project));
if (delegate != null) {
registerCodeStyleManager(project, delegate);
}
}
/**
* Dmitry Jemerov in unrelated discussion: "Trying to replace IDEA's core components with your custom
* implementations is something that we consider a very bad idea, and it's pretty much guaranteed to break in future
* versions of IntelliJ IDEA. I certainly hope that you won't stomp on any other plugins doing that, because no one
* else is doing it. It would be better to find another approach to solving your problem."
*
* LoL
*/
private static void registerCodeStyleManager(@NotNull Project project, @NotNull CodeStyleManager manager) {
LOG.info("Registering code style manager '" + manager + "' for project '" + project.getName() + "'");
MutablePicoContainer container = (MutablePicoContainer) project.getPicoContainer();
container.unregisterComponent(CODE_STYLE_MANAGER_KEY);
container.registerComponentInstance(CODE_STYLE_MANAGER_KEY, manager);
}
}