Merge remote-tracking branch 'origin/master'

This commit is contained in:
Kirill Likhodedov
2011-12-20 13:11:11 +03:00
34 changed files with 1545 additions and 854 deletions
@@ -21,12 +21,14 @@ import com.intellij.ide.structureView.StructureView;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.util.FileStructureDialog;
import com.intellij.ide.util.FileStructurePopup;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiDocumentManager;
@@ -55,13 +57,24 @@ public class ViewStructureAction extends AnAction {
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.file.structure");
Navigatable navigatable = e.getData(PlatformDataKeys.NAVIGATABLE);
DialogWrapper dialog = createDialog(editor, project, navigatable, fileEditor);
if (dialog != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
dialog.setTitle(virtualFile.getName());
if (Registry.is("file.structure.tree.mode")) {
FileStructurePopup popup = createPopup(editor, project, navigatable, fileEditor);
if (popup != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
popup.setTitle(virtualFile.getName());
}
popup.show();
}
} else {
DialogWrapper dialog = createDialog(editor, project, navigatable, fileEditor);
if (dialog != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
dialog.setTitle(virtualFile.getName());
}
dialog.show();
}
dialog.show();
}
}
@@ -72,6 +85,14 @@ public class ViewStructureAction extends AnAction {
StructureView structureView = structureViewBuilder.createStructureView(fileEditor, project);
return createStructureViewBasedDialog(structureView.getTreeModel(), editor, project, navigatable, structureView);
}
@Nullable
private static FileStructurePopup createPopup(final Editor editor, Project project, Navigatable navigatable, final FileEditor fileEditor) {
final StructureViewBuilder structureViewBuilder = fileEditor.getStructureViewBuilder();
if (structureViewBuilder == null) return null;
StructureView structureView = structureViewBuilder.createStructureView(fileEditor, project);
return createStructureViewPopup(structureView.getTreeModel(), editor, project, navigatable, structureView);
}
public static FileStructureDialog createStructureViewBasedDialog(final StructureViewModel structureViewModel,
final Editor editor,
@@ -80,7 +101,14 @@ public class ViewStructureAction extends AnAction {
final @NotNull Disposable alternativeDisposable) {
return new FileStructureDialog(structureViewModel, editor, project, navigatable, alternativeDisposable, true);
}
public static FileStructurePopup createStructureViewPopup(final StructureViewModel structureViewModel,
final Editor editor,
final Project project,
final Navigatable navigatable,
final @NotNull Disposable alternativeDisposable) {
return new FileStructurePopup(structureViewModel, editor, project, navigatable, alternativeDisposable, true);
}
public void update(AnActionEvent event) {
Presentation presentation = event.getPresentation();
DataContext dataContext = event.getDataContext();
@@ -36,7 +36,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
class StructureTreeBuilder extends AbstractTreeBuilder {
public class StructureTreeBuilder extends AbstractTreeBuilder {
private final Project myProject;
private final StructureViewModel myStructureModel;
@@ -733,7 +733,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
}
//todo [kirillk] dirty hack for discovering invalid psi elements, to delegate it to a proper place after 8.1
private static boolean isValid(Object treeElement) {
public static boolean isValid(Object treeElement) {
if (treeElement instanceof StructureViewTreeElementWrapper) {
final StructureViewTreeElementWrapper wrapper = (StructureViewTreeElementWrapper)treeElement;
if (wrapper.getValue() instanceof PsiTreeElementBase) {
@@ -744,7 +744,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
return true;
}
static class StructureViewTreeElementWrapper extends TreeElementWrapper implements NodeDescriptorProvidingKey {
public static class StructureViewTreeElementWrapper extends TreeElementWrapper implements NodeDescriptorProvidingKey {
private long childrenStamp = -1;
private long modificationCountForChildren = ourSettingsModificationCount;
@@ -0,0 +1,528 @@
/*
* Copyright 2000-2011 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.util;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.commander.CommanderPanel;
import com.intellij.ide.commander.ProjectListBuilder;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
import com.intellij.ide.structureView.newStructureView.StructureTreeBuilder;
import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
import com.intellij.ide.structureView.newStructureView.TreeActionsOwner;
import com.intellij.ide.structureView.newStructureView.TreeModelWrapper;
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.ide.util.treeView.smartTree.*;
import com.intellij.lang.LanguageStructureViewBuilder;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SpeedSearchBase;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.ui.docking.DockManager;
import com.intellij.ui.speedSearch.SpeedSearchSupply;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author Konstantin Bulenkov
*/
public class FileStructurePopup implements Disposable {
private final Editor myEditor;
private final Navigatable myNavigatable;
private final Project myProject;
private final StructureViewModel myTreeModel;
private final StructureViewModel myBaseTreeModel;
private final MyTreeActionsOwner myTreeActionsOwner;
private JBPopup myPopup;
@NonNls private static final String ourPropertyKey = "FileStructure.narrowDown";
private boolean myShouldNarrowDown = false;
private Tree myTree;
private AbstractTreeBuilder myAbstractTreeBuilder;
private String myTitle;
public FileStructurePopup(StructureViewModel structureViewModel,
@Nullable Editor editor,
Project project,
Navigatable navigatable,
@NotNull final Disposable auxDisposable,
final boolean applySortAndFilter) {
myProject = project;
myEditor = editor;
myNavigatable = navigatable;
myBaseTreeModel = structureViewModel;
if (applySortAndFilter) {
myTreeActionsOwner = new MyTreeActionsOwner();
myTreeModel = new TreeModelWrapper(structureViewModel, myTreeActionsOwner);
}
else {
myTreeActionsOwner = null;
myTreeModel = structureViewModel;
}
PsiFile psiFile = getPsiFile(project);
final PsiElement psiElement = getCurrentElement(psiFile);
//myDialog.setUndecorated(true);
if (psiElement != null) {
if (structureViewModel.shouldEnterElement(psiElement)) {
//myCommanderPanel.getBuilder().enterElement(psiElement, PsiUtilBase.getVirtualFile(psiElement));
}
else {
//myCommanderPanel.getBuilder().selectElement(psiElement, PsiUtilBase.getVirtualFile(psiElement));
}
}
SmartTreeStructure treeStructure = new SmartTreeStructure(project, myTreeModel){
public void rebuildTree() {
if (!myPopup.isDisposed()) {
super.rebuildTree();
}
}
public boolean isToBuildChildrenInBackground(final Object element) {
return getRootElement() == element;
}
protected TreeElementWrapper createTree() {
return new StructureViewComponent.StructureViewTreeElementWrapper(myProject, myModel.getRoot(), myModel);
}
@Override
public String toString() {
return "structure view tree structure(model=" + myTreeModel + ")";
}
};
final DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode(treeStructure.getRootElement()));
myTree = new Tree(model);
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true);
myAbstractTreeBuilder = new StructureTreeBuilder(project, myTree,
(DefaultTreeModel)myTree.getModel(),treeStructure, myTreeModel) {
@Override
protected boolean validateNode(Object child) {
return StructureViewComponent.isValid(child);
}
};
}
public void show() {
final JComponent panel = createCenterPanel();
new MnemonicHelper().register(panel);
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, null)
.setTitle(myTitle)
.setResizable(true)
.setFocusable(true)
.setMovable(true)
.setDimensionServiceKey(null, getDimensionServiceKey(), false)
.createPopup();
myPopup.showInCenterOf(myEditor.getContentComponent());
new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true);
myAbstractTreeBuilder.expandAll(new Runnable() {
@Override
public void run() {
IdeFocusManager.getInstance(myProject).requestFocus(myTree, true);
myAbstractTreeBuilder.queueUpdate().doWhenDone(new Runnable() {
@Override
public void run() {
myAbstractTreeBuilder.expandAll(null);
}
});
}
});
}
protected PsiFile getPsiFile(final Project project) {
return PsiDocumentManager.getInstance(project).getPsiFile(myEditor.getDocument());
}
@Nullable
protected Border createContentPaneBorder() {
return null;
}
public void dispose() {
}
protected String getDimensionServiceKey() {
return DockManager.getInstance(myProject).getDimensionKeyForFocus("#com.intellij.ide.util.FileStructureDialog");
}
@Nullable
protected PsiElement getCurrentElement(@Nullable final PsiFile psiFile) {
if (psiFile == null) return null;
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
Object elementAtCursor = myTreeModel.getCurrentEditorElement();
if (elementAtCursor instanceof PsiElement) {
return (PsiElement)elementAtCursor;
}
return null;
}
protected JComponent createCenterPanel() {
List<FileStructureFilter> fileStructureFilters = new ArrayList<FileStructureFilter>();
List<FileStructureNodeProvider> fileStructureNodeProviders = new ArrayList<FileStructureNodeProvider>();
if (myTreeActionsOwner != null) {
for(Filter filter: myBaseTreeModel.getFilters()) {
if (filter instanceof FileStructureFilter) {
final FileStructureFilter fsFilter = (FileStructureFilter)filter;
myTreeActionsOwner.setActionIncluded(fsFilter, true);
fileStructureFilters.add(fsFilter);
}
}
if (myBaseTreeModel instanceof ProvidingTreeModel) {
for (NodeProvider provider : ((ProvidingTreeModel)myBaseTreeModel).getNodeProviders()) {
if (provider instanceof FileStructureNodeProvider) {
fileStructureNodeProviders.add((FileStructureNodeProvider)provider);
}
}
}
}
//new AnAction() {
// public void actionPerformed(AnActionEvent e) {
// final boolean succeeded = myCommanderPanel.navigateSelectedElement();
// if (succeeded) {
// unregisterCustomShortcutSet(myCommanderPanel);
// }
// }
//}.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), myCommanderPanel);
//myCommanderPanel.setPreferredSize(new Dimension(400, 500));
JPanel panel = new JPanel(new BorderLayout());
JPanel comboPanel = new JPanel(new GridLayout(0, 2, 0, 0));
addNarrowDownCheckbox(comboPanel);
for(FileStructureFilter filter: fileStructureFilters) {
addCheckbox(comboPanel, filter);
}
for (FileStructureNodeProvider provider : fileStructureNodeProviders) {
addCheckbox(comboPanel, provider);
}
//myCommanderPanel.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP));
panel.add(comboPanel, BorderLayout.NORTH);
panel.add(ScrollPaneFactory.createScrollPane(myAbstractTreeBuilder.getTree()), BorderLayout.CENTER);
//new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
return panel;
}
protected boolean isShowRoot(final PsiFile psiFile) {
StructureViewBuilder viewBuilder = LanguageStructureViewBuilder.INSTANCE.getStructureViewBuilder(psiFile);
return viewBuilder instanceof TreeBasedStructureViewBuilder && ((TreeBasedStructureViewBuilder)viewBuilder).isRootNodeShown();
}
private void addNarrowDownCheckbox(final JPanel panel) {
final JCheckBox checkBox = new JCheckBox(IdeBundle.message("checkbox.narrow.down.the.list.on.typing"));
checkBox.setSelected(PropertiesComponent.getInstance().isTrueValue(ourPropertyKey));
checkBox.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
myShouldNarrowDown = checkBox.isSelected();
PropertiesComponent.getInstance().setValue(ourPropertyKey, Boolean.toString(myShouldNarrowDown));
myAbstractTreeBuilder.queueUpdate();
}
});
checkBox.setFocusable(false);
panel.add(checkBox);
//,new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
}
private void addCheckbox(final JPanel panel, final TreeAction action) {
String text = action instanceof FileStructureFilter ? ((FileStructureFilter)action).getCheckBoxText() :
action instanceof FileStructureNodeProvider ? ((FileStructureNodeProvider)action).getCheckBoxText() : null;
if (text == null) return;
Shortcut[] shortcuts = action instanceof FileStructureFilter ?
((FileStructureFilter)action).getShortcut() : ((FileStructureNodeProvider)action).getShortcut();
final JCheckBox chkFilter = new JCheckBox();
chkFilter.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
PsiElement currentParent = null;
final AbstractTreeNode parentNode = null;//todo myAbstractTreeBuilder.getUi().getRootNode().;
final Object value = null; //todo parentNode.getValue();
if (value instanceof StructureViewTreeElement) {
final Object elementValue = ((StructureViewTreeElement)value).getValue();
if (elementValue instanceof PsiElement) {
currentParent = (PsiElement) elementValue;
}
}
final boolean state = chkFilter.isSelected();
myTreeActionsOwner.setActionIncluded(action, action instanceof FileStructureFilter ? !state : state);
myAbstractTreeBuilder.queueUpdate();
if (currentParent != null) {
boolean oldNarrowDown = myShouldNarrowDown;
myShouldNarrowDown = false;
try {
//todo builder.enterElement(currentParent, PsiUtilBase.getVirtualFile(currentParent));
}
finally {
myShouldNarrowDown = oldNarrowDown;
}
}
myAbstractTreeBuilder.queueUpdate();
if (SpeedSearchBase.hasActiveSpeedSearch(myTree)) {
final SpeedSearchSupply supply = SpeedSearchSupply.getSupply(myTree);
if (supply != null && supply.isPopupActive()) supply.refreshSelection();
}
}
});
chkFilter.setFocusable(false);
if (shortcuts.length > 0) {
text += " (" + KeymapUtil.getShortcutText(shortcuts[0]) + ")";
new AnAction() {
public void actionPerformed(final AnActionEvent e) {
chkFilter.doClick();
}
}.registerCustomShortcutSet(new CustomShortcutSet(shortcuts), myTree);
}
chkFilter.setText(text);
panel.add(chkFilter);
//,new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0));
}
@Nullable
protected JComponent createSouthPanel() {
return null;
}
public void setTitle(String title) {
myTitle = title;
}
private class MyCommanderPanel extends CommanderPanel implements DataProvider {
@Override
protected boolean shouldDrillDownOnEmptyElement(final AbstractTreeNode node) {
return false;
}
public MyCommanderPanel(Project _project) {
super(_project, false, true);
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
myListSpeedSearch.addChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
ProjectListBuilder builder = (ProjectListBuilder)getBuilder();
if (builder == null) {
return;
}
builder.addUpdateRequest(hasPrefixShortened(evt));
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
int index = myList.getSelectedIndex();
if (index != -1 && index < myList.getModel().getSize()) {
myList.clearSelection();
ListScrollingUtil.selectItem(myList, index);
}
else {
ListScrollingUtil.ensureSelectionExists(myList);
}
}
});
myList.repaint(); // to update match highlighting
}
});
myListSpeedSearch.setComparator(createSpeedSearchComparator());
}
private boolean hasPrefixShortened(final PropertyChangeEvent evt) {
return evt.getNewValue() != null && evt.getOldValue() != null &&
((String)evt.getNewValue()).length() < ((String)evt.getOldValue()).length();
}
public boolean navigateSelectedElement() {
final Ref<Boolean> succeeded = new Ref<Boolean>();
final CommandProcessor commandProcessor = CommandProcessor.getInstance();
commandProcessor.executeCommand(myProject, new Runnable() {
public void run() {
succeeded.set(MyCommanderPanel.super.navigateSelectedElement());
IdeDocumentHistory.getInstance(myProject).includeCurrentCommandAsNavigation();
}
}, "Navigate", null);
if (succeeded.get()) {
myPopup.cancel();
}
return succeeded.get();
}
public Object getData(String dataId) {
Object selectedElement = ContainerUtil.getFirstItem(myAbstractTreeBuilder.getSelectedElements());
if (selectedElement instanceof TreeElement) selectedElement = ((StructureViewTreeElement)selectedElement).getValue();
if (PlatformDataKeys.NAVIGATABLE.is(dataId)) {
return selectedElement instanceof Navigatable ? selectedElement : myNavigatable;
}
if (OpenFileDescriptor.NAVIGATE_IN_EDITOR.is(dataId)) return myEditor;
return getDataImpl(dataId);
}
public String getEnteredPrefix() {
return myListSpeedSearch.getEnteredPrefix();
}
public void updateSpeedSearch() {
myListSpeedSearch.refreshSelection();
}
public void scrollSelectionInView() {
int selectedIndex = myList.getSelectedIndex();
if (selectedIndex >= 0) {
ListScrollingUtil.ensureIndexIsVisible(myList, selectedIndex, 0);
}
}
}
private class MyStructureTreeStructure extends SmartTreeStructure {
public MyStructureTreeStructure(Project project) {
super(project, myTreeModel);
}
public Object[] getChildElements(Object element) {
Object[] childElements = super.getChildElements(element);
if (!myShouldNarrowDown) {
return childElements;
}
String enteredPrefix = null;//todo myCommanderPanel.getEnteredPrefix();
if (enteredPrefix == null) {
return childElements;
}
ArrayList<Object> filteredElements = new ArrayList<Object>(childElements.length);
SpeedSearchBase.SpeedSearchComparator speedSearchComparator = createSpeedSearchComparator();
for (Object child : childElements) {
if (child instanceof AbstractTreeNode) {
Object value = ((AbstractTreeNode)child).getValue();
if (value instanceof TreeElement) {
String name = ((TreeElement)value).getPresentation().getPresentableText();
if (name == null) {
continue;
}
if (speedSearchComparator.matchingFragments(enteredPrefix, name) == null) {
continue;
}
}
}
filteredElements.add(child);
}
return ArrayUtil.toObjectArray(filteredElements);
}
public void rebuildTree() {
getChildElements(getRootElement()); // for some reason necessary to rebuild tree correctly
super.rebuildTree();
}
}
private static SpeedSearchBase.SpeedSearchComparator createSpeedSearchComparator() {
return new SpeedSearchBase.SpeedSearchComparator(false);
}
private class MyTreeActionsOwner implements TreeActionsOwner {
private final Set<TreeAction> myActions = new HashSet<TreeAction>();
public void setActionActive(String name, boolean state) {
}
public boolean isActionActive(String name) {
for (final Sorter sorter : myBaseTreeModel.getSorters()) {
if (sorter.getName().equals(name)) {
if (!sorter.isVisible()) return true;
}
}
for(TreeAction action: myActions) {
if (action.getName().equals(name)) return true;
}
return Sorter.ALPHA_SORTER_ID.equals(name);
}
public void setActionIncluded(final TreeAction filter, final boolean selected) {
if (selected) {
myActions.add(filter);
}
else {
myActions.remove(filter);
}
}
}
}
@@ -594,9 +594,9 @@ public class IdeEventQueue extends EventQueue {
}
boolean mouseEventsAhead = isMouseEventAhead(e);
boolean focusTransferred = IdeFocusManager.getGlobalInstance().isFocusBeingTransferred();
boolean focusTransferredNow = IdeFocusManager.getGlobalInstance().isFocusBeingTransferred();
boolean okToFixFocus = !mouseEventsAhead && focusTransferred;
boolean okToFixFocus = !mouseEventsAhead && !focusTransferredNow;
if (okToFixFocus) {
Window showingWindow = mgr.getActiveWindow();
@@ -158,6 +158,9 @@ public abstract class RecentProjectsManagerBase implements PersistentStateCompon
final List<String> paths = new ArrayList<String>();
synchronized (myState) {
outer: for (String recentPath : myState.recentPaths) {
if (recentPath == null) {
continue;
}
for (Project openProject : openProjects) {
final String path = getProjectPath(openProject);
@@ -269,7 +272,7 @@ public abstract class RecentProjectsManagerBase implements PersistentStateCompon
}
}
@Nullable
@NotNull
private static String getProjectName(String path) {
final File file = new File(path);
if (file.isDirectory()) {
@@ -294,14 +297,12 @@ public abstract class RecentProjectsManagerBase implements PersistentStateCompon
}
}
}
} else {
return file.getName();
}
} else {
return file.getName();
}
else {
return FileUtil.getNameWithoutExtension(file.getName());
}
return null;
}
private class MyAppLifecycleListener extends AppLifecycleListener.Adapter {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class PluginsUsagesCollector extends UsagesCollector {
public class DisabledPluginsUsagesCollector extends UsagesCollector {
private static final String GROUP_ID = "disabled-plugins";
@NotNull
@@ -0,0 +1,56 @@
/*
* Copyright 2000-2011 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.plugins;
import com.intellij.internal.statistic.UsagesCollector;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
public class NonBundledPluginsUsagesCollector extends UsagesCollector {
private static final String GROUP_ID = "non-bundled-plugins";
@NotNull
public GroupDescriptor getGroupId() {
return GroupDescriptor.create(GROUP_ID, GroupDescriptor.HIGHER_PRIORITY);
}
@NotNull
public Set<UsageDescriptor> getUsages(@Nullable Project project) {
final IdeaPluginDescriptor[] plugins = PluginManager.getPlugins();
final List<IdeaPluginDescriptor> nonBundledEnabledPlugins = ContainerUtil.filter(plugins, new Condition<IdeaPluginDescriptor>() {
public boolean value(final IdeaPluginDescriptor d) {
return d.isEnabled() && !d.isBundled() && d.getPluginId() != null;
}
});
return ContainerUtil.map2Set(nonBundledEnabledPlugins, new Function<IdeaPluginDescriptor, UsageDescriptor>() {
@Override
public UsageDescriptor fun(IdeaPluginDescriptor descriptor) {
return new UsageDescriptor(descriptor.getPluginId().getIdString(), 1);
}
});
}
}
@@ -40,7 +40,7 @@ public abstract class AbstractApplicationUsagesCollector extends UsagesCollector
public void persistProjectUsages(@NotNull Project project,
@NotNull Set<UsageDescriptor> usages,
@NotNull ApplicationStatisticsPersistence persistence) {
persistence.persistFrameworks(getGroupId(), project, usages);
persistence.persistUsages(getGroupId(), project, usages);
}
@NotNull
@@ -50,20 +50,20 @@ public abstract class AbstractApplicationUsagesCollector extends UsagesCollector
@NotNull
public Set<UsageDescriptor> getApplicationUsages(@NotNull final ApplicationStatisticsPersistence persistence) {
final Map<String, Integer> facets = new HashMap<String, Integer>();
final Map<String, Integer> result = new HashMap<String, Integer>();
for (Set<UsageDescriptor> frameworks : persistence.getApplicationData(getGroupId()).values()) {
for (UsageDescriptor framework : frameworks) {
final String key = framework.getKey();
final Integer count = facets.get(key);
facets.put(key, count == null ? 1 : count.intValue() + 1);
for (Set<UsageDescriptor> usageDescriptors : persistence.getApplicationData(getGroupId()).values()) {
for (UsageDescriptor usageDescriptor : usageDescriptors) {
final String key = usageDescriptor.getKey();
final Integer count = result.get(key);
result.put(key, count == null ? 1 : count.intValue() + 1);
}
}
return ContainerUtil.map2Set(facets.entrySet(), new Function<Map.Entry<String, Integer>, UsageDescriptor>() {
return ContainerUtil.map2Set(result.entrySet(), new Function<Map.Entry<String, Integer>, UsageDescriptor>() {
@Override
public UsageDescriptor fun(Map.Entry<String, Integer> facet) {
return new UsageDescriptor(facet.getKey(), facet.getValue());
public UsageDescriptor fun(Map.Entry<String, Integer> entry) {
return new UsageDescriptor(entry.getKey(), entry.getValue());
}
});
}
@@ -42,7 +42,7 @@ public class RemotelyConfigurableStatisticsService implements StatisticsService
return new StatisticsResult(StatisticsResult.ResultCode.SEND, content);
}
catch (Exception e) {
return new StatisticsResult(StatisticsResult.ResultCode.SEND_WITH_ERRORS, e.getMessage() != null ? e.getMessage() : "NPE");
return new StatisticsResult(StatisticsResult.ResultCode.SENT_WITH_ERRORS, e.getMessage() != null ? e.getMessage() : "NPE");
}
}
}
@@ -32,5 +32,5 @@ public class StatisticsResult {
return code;
}
public enum ResultCode {SEND, NOT_PERMITTED_SERVER, NOT_PERMITTED_USER, ERROR_IN_CONFIG, NOT_PERMITTED_TIMEOUT, NOTHING_TO_SEND, SEND_WITH_ERRORS}
public enum ResultCode {SEND, NOT_PERMITTED_SERVER, NOT_PERMITTED_USER, ERROR_IN_CONFIG, NOT_PERMITTED_TIMEOUT, NOTHING_TO_SEND, SENT_WITH_ERRORS}
}
@@ -15,11 +15,11 @@ public abstract class ApplicationStatisticsPersistence {
public ApplicationStatisticsPersistence() {
}
public void persistFrameworks(@NotNull GroupDescriptor groupDescriptor, @NotNull Project project, @NotNull Set<UsageDescriptor> frameworks) {
public void persistUsages(@NotNull GroupDescriptor groupDescriptor, @NotNull Project project, @NotNull Set<UsageDescriptor> usageDescriptors) {
if (!myApplicationData.containsKey(groupDescriptor)) {
myApplicationData.put(groupDescriptor, new HashMap<String, Set<UsageDescriptor>>());
}
myApplicationData.get(groupDescriptor).put(project.getName(), frameworks);
myApplicationData.get(groupDescriptor).put(project.getName(), usageDescriptors);
}
@NotNull
@@ -1330,6 +1330,11 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
}
public void _setBounds(Rectangle bounds) {
Rectangle currentBounds = getBounds();
if (currentBounds.width != bounds.width || currentBounds.height != bounds.height) {
invalidateShadowImage();
}
super.setBounds(bounds);
if (myCloseRec.getParent() == null && getParent() != null) {
myLayeredPane.add(myCloseRec);
@@ -1357,6 +1362,11 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
}
}
private void invalidateShadowImage() {
myImage = null;
myShadow = null;
}
public void repaintButton() {
myCloseRec.repaint();
}
@@ -169,3 +169,4 @@ show.anonymous.in.structure.view.description=Enables Java anonymous classes in S
enable.groovy.hotswap=true
enable.groovy.hotswap.description=Whether IDEA should add a special java agent to the debugged process which allows to hot-swap Groovy changes in some cases
file.structure.tree.mode=false
@@ -228,7 +228,8 @@
<bundledKeymapProvider implementation="com.intellij.openapi.keymap.impl.DefaultBundledKeymaps"/>
<!-- <checkinHandlerFactory implementation="com.intellij.openapi.vcs.CheckRemoteStatusCheckinHandlerFactory"/> -->
<statistics.usagesCollector implementation="com.intellij.ide.plugins.PluginsUsagesCollector"/>
<statistics.usagesCollector implementation="com.intellij.ide.plugins.DisabledPluginsUsagesCollector"/>
<statistics.usagesCollector implementation="com.intellij.ide.plugins.NonBundledPluginsUsagesCollector"/>
<statistics.usagesCollector implementation="com.intellij.featureStatistics.FeaturesUsageCollector"/>
<statistics.usagesCollector implementation="com.intellij.openapi.vcs.statistics.VcsUsagesCollector"/>
@@ -52,7 +52,7 @@ public class RemotelyConfigurableStatServiceTest extends TestCase {
}
});
final StatisticsResult result = service.send();
Assert.assertEquals(StatisticsResult.ResultCode.SEND_WITH_ERRORS, result.getCode());
Assert.assertEquals(StatisticsResult.ResultCode.SENT_WITH_ERRORS, result.getCode());
}
public void testRemotelyDisabledTransmission() {
@@ -295,7 +295,6 @@ default.initializers.are.not.allowed.in.abstract.method=Default initializers are
groovy.does.not.support.constructor.type.arguments=Groovy does not support constructor type arguments
illegal.escape.character.in.string.literal=Illegal escape character in string literal
dollar.slash.end.expected=Dollar slash ending expected
regex.cannot.be.first.argument.of.command.method.call=Dollar-slashy strings cannot be the first argument of a command method call
add.parentheses=Add parentheses
add.parentheses.to.command.method.call=Add parentheses to command method call
dollar.slash.strings.are.not.allowed.in.0=Dollar-slash strings are not allowed in Groovy {0}
dollar.slash.strings.are.not.allowed.in.0=Dollar slashy strings are not allowed in Groovy {0}
@@ -279,9 +279,14 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
private void checkStringNameIdentifier(GrReferenceExpression ref) {
final PsiElement nameElement = ref.getReferenceNameElement();
if (nameElement == null) return;
if (!GroovyTokenTypes.mSTRING_LITERAL.equals(nameElement.getNode().getElementType())) return;
final String text = nameElement.getText();
checkStringLiteral(nameElement, text);
final IElementType elementType = nameElement.getNode().getElementType();
if (elementType == GroovyTokenTypes.mSTRING_LITERAL || elementType == GroovyTokenTypes.mGSTRING_LITERAL) {
checkStringLiteral(nameElement, nameElement.getText());
}
else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
checkRegexLiteral(nameElement);
}
}
/*
@@ -856,19 +861,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
myHolder
.createErrorAnnotation(regex, GroovyBundle.message("dollar.slash.strings.are.not.allowed.in.0", config.getSDKVersion(regex)));
}
if (regex instanceof GrRegex &&
regex.getParent() instanceof GrCommandArgumentList &&
((GrCommandArgumentList)regex.getParent()).getAllArguments()[0] == regex ||
!(regex instanceof GrRegex) &&
regex.getParent().getParent() instanceof GrCommandArgumentList &&
((GrCommandArgumentList)regex.getParent().getParent()).getAllArguments()[0] == regex.getParent()
) {
final Annotation annotation =
myHolder.createErrorAnnotation(regex, GroovyBundle.message("regex.cannot.be.first.argument.of.command.method.call"));
annotation.registerFix(new AddParenthesesFix());
return;
}
}
@@ -82,7 +82,7 @@ public class GeeseUtil {
}
@Nullable
static Alignment calculateRBraceAlignment(PsiElement rBrace, Map<PsiElement, Alignment> alignments, Map<PsiElement, GroovyBlock> blocks) {
static Alignment calculateRBraceAlignment(PsiElement rBrace, Map<PsiElement, Alignment> alignments) {
int leadingBraceCount = 0;
PsiElement next;
@@ -146,11 +146,7 @@ public class GeeseUtil {
Alignment alignment = alignments.get(cur);
if (alignment == null) {
final GroovyBlock block = blocks.get(cur);
alignment = Alignment.createAlignment(true);
if (block != null) {
block.setAlignment(alignment);
}
alignments.put(cur, alignment);
}
return alignment;
@@ -55,7 +55,7 @@ import java.util.Map;
*
* @author ilyas
*/
public abstract class GroovyBlock implements Block, GroovyElementTypes, ASTBlock {
public class GroovyBlock implements Block, GroovyElementTypes, ASTBlock {
final protected ASTNode myNode;
protected Alignment myAlignment;
final protected Indent myIndent;
@@ -63,7 +63,6 @@ public abstract class GroovyBlock implements Block, GroovyElementTypes, ASTBlock
final protected CommonCodeStyleSettings mySettings;
final protected GroovyCodeStyleSettings myGroovySettings;
final protected Map<PsiElement, Alignment> myInnerAlignments;
final protected Map<PsiElement, GroovyBlock> myBlocks;
protected List<Block> mySubBlocks = null;
@@ -73,12 +72,10 @@ public abstract class GroovyBlock implements Block, GroovyElementTypes, ASTBlock
@Nullable final Wrap wrap,
final CommonCodeStyleSettings settings,
GroovyCodeStyleSettings groovySettings,
@NotNull Map<PsiElement, Alignment> innerAlignments, Map<PsiElement, GroovyBlock> blocks) {
@NotNull Map<PsiElement, Alignment> innerAlignments) {
myNode = node;
myBlocks = blocks;
if (groovySettings.USE_FLYING_GEESE_BRACES) {
PsiElement psi = myNode.getPsi();
myBlocks.put(psi, this);
if (alignment == null) {
alignment = innerAlignments.get(psi);
}
@@ -119,8 +116,12 @@ public abstract class GroovyBlock implements Block, GroovyElementTypes, ASTBlock
}
@NotNull
@Override
public List<Block> getSubBlocks() {
return mySubBlocks;
if (mySubBlocks == null) {
mySubBlocks = new GroovyBlockGenerator(this).generateSubBlocks();
}
return mySubBlocks;
}
@Nullable
@@ -228,10 +229,6 @@ public abstract class GroovyBlock implements Block, GroovyElementTypes, ASTBlock
return isIncomplete(myNode);
}
public void setAlignment(Alignment alignment) {
myAlignment = alignment;
}
/**
* @param node Tree node
* @return true if node is incomplete
@@ -82,7 +82,6 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
private final Wrap myWrap;
private final CommonCodeStyleSettings mySettings;
private final Map<PsiElement,Alignment> myInnerAlignments;
private final Map<PsiElement,GroovyBlock> myBlocks;
private final GroovyCodeStyleSettings myGroovySettings;
public GroovyBlockGenerator(GroovyBlock block) {
@@ -93,7 +92,6 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
mySettings = myBlock.getSettings();
myInnerAlignments = myBlock.getInnerAlignments();
myGroovySettings = myBlock.getGroovySettings();
myBlocks = myBlock.myBlocks;
}
@@ -136,8 +134,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
for (ASTNode childNode : children) {
if (childNode.getTextRange().getLength() > 0) {
final Indent indent = GroovyIndentProcessor.getChildIndent(myBlock, childNode);
subBlocks.add(new GroovySimpleBlock(childNode, myAlignment, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks));
subBlocks.add(new GroovyBlock(childNode, myAlignment, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
}
return subBlocks;
@@ -158,8 +155,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
final Alignment newAlignment = mustAlign(blockPsi, astNodes) ? Alignment.createAlignment() : null;
for (ASTNode childNode : astNodes) {
final Indent indent = GroovyIndentProcessor.getChildIndent(myBlock, childNode);
subBlocks.add(new GroovySimpleBlock(childNode, isKeyword(childNode) ? null : newAlignment, indent, myWrap, mySettings, myGroovySettings,
myInnerAlignments, myBlocks));
subBlocks.add(new GroovyBlock(childNode, isKeyword(childNode) ? null : newAlignment, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
return subBlocks;
}
@@ -172,8 +168,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
for (ASTNode childNode : children) {
final Indent indent = GroovyIndentProcessor.getChildIndent(myBlock, childNode);
Alignment alignmentToUse = classLevel ? myAlignment : myInnerAlignments.get(childNode.getPsi());
subBlocks.add(new GroovySimpleBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks));
subBlocks.add(new GroovyBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
return subBlocks;
}
@@ -182,8 +177,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
final ArrayList<Block> subBlocks = new ArrayList<Block>();
for (ASTNode childNode : visibleChildren(myNode)) {
final Indent indent = GroovyIndentProcessor.getChildIndent(myBlock, childNode);
subBlocks.add(new GroovySimpleBlock(childNode, myInnerAlignments.get(childNode.getPsi()), indent, myWrap, mySettings, myGroovySettings,
myInnerAlignments, myBlocks));
subBlocks.add(new GroovyBlock(childNode, myInnerAlignments.get(childNode.getPsi()), indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
return subBlocks;
}
@@ -232,9 +226,9 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
}
}
}
else if (GeeseUtil.isClosureRBrace(psi) && myGroovySettings.USE_FLYING_GEESE_BRACES) {
/*else if (GeeseUtil.isClosureRBrace(psi) && myGroovySettings.USE_FLYING_GEESE_BRACES) {
myInnerAlignments.put(psi, GeeseUtil.calculateRBraceAlignment(psi, myInnerAlignments, myBlocks));
}
}*/
else {
if (psi instanceof PsiComment) {
PsiElement prev = psi.getPrevSibling();
@@ -325,22 +319,19 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
final int start = myNode.getTextRange().getStartOffset();
final int end = myNode.getTextRange().getEndOffset();
subBlocks.add(new GroovySimpleBlock(myNode, myAlignment, Indent.getNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks) {
subBlocks.add(new GroovyBlock(myNode, myAlignment, Indent.getNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments) {
@NotNull
public TextRange getTextRange() {
return new TextRange(start, start + 3);
}
});
subBlocks.add(new GroovySimpleBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks) {
subBlocks.add(new GroovyBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments) {
@NotNull
public TextRange getTextRange() {
return new TextRange(start + 3, end - 3);
}
});
subBlocks.add(new GroovySimpleBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks) {
subBlocks.add(new GroovyBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments) {
@NotNull
public TextRange getTextRange() {
return new TextRange(end - 3, end);
@@ -354,15 +345,13 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
final int start = myNode.getTextRange().getStartOffset();
final int end = myNode.getTextRange().getEndOffset();
subBlocks.add(new GroovySimpleBlock(myNode, myAlignment, Indent.getNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks) {
subBlocks.add(new GroovyBlock(myNode, myAlignment, Indent.getNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments) {
@NotNull
public TextRange getTextRange() {
return new TextRange(start, start + 3);
}
});
subBlocks.add(new GroovySimpleBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks) {
subBlocks.add(new GroovyBlock(myNode, myAlignment, Indent.getAbsoluteNoneIndent(), myWrap, mySettings, myGroovySettings, myInnerAlignments) {
@NotNull
public TextRange getTextRange() {
return new TextRange(start + 3, end);
@@ -444,8 +433,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
PsiElement psi = childNode.getPsi();
if (!(psi instanceof GrBinaryExpression)) {
Alignment alignmentToUse = op == psi ? myInnerAlignments.get(op) : alignment;
list.add(new GroovySimpleBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments,
myBlocks));
list.add(new GroovyBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
}
if (myExpr.getRightOperand() instanceof GrBinaryExpression) {
@@ -474,8 +462,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
}
if (i < grandChildren.size()) {
LOG.assertTrue(nameElement == grandChildren.get(i).getPsi());
list.add(new MethodCallWithoutQualifierBlock(nameElement, null, myWrap, mySettings, myGroovySettings, topLevel, children, elem,
myInnerAlignments, myBlocks));
list.add(new MethodCallWithoutQualifierBlock(nameElement, null, myWrap, mySettings, myGroovySettings, topLevel, children, elem, myInnerAlignments));
}
return;
}
@@ -496,7 +483,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
else {
Alignment alignmentToUse = myInnerAlignments.get(fst.getPsi());
Indent indent = Indent.getContinuationWithoutFirstIndent();
list.add(new GroovySimpleBlock(fst, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments, myBlocks));
list.add(new GroovyBlock(fst, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
addNestedChildrenSuffix(list, alignment, topLevel, children, limit);
}
@@ -510,7 +497,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
Indent.getContinuationWithoutFirstIndent() :
Indent.getNoneIndent();
Alignment alignmentToUse = TokenSets.DOTS.contains(type) ? alignment : myInnerAlignments.get(childNode.getPsi());
list.add(new GroovySimpleBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments, myBlocks));
list.add(new GroovyBlock(childNode, alignmentToUse, indent, myWrap, mySettings, myGroovySettings, myInnerAlignments));
}
}
}
@@ -21,6 +21,7 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.TokenType;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
@@ -36,6 +37,8 @@ import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import java.util.Map;
/**
* @author ilyas
*/
@@ -50,9 +53,24 @@ public class GroovyFormattingModelBuilder implements FormattingModelBuilder {
assert astNode != null;
CommonCodeStyleSettings groovySettings = settings.getCommonSettings(GroovyFileType.GROOVY_LANGUAGE);
GroovyCodeStyleSettings customSettings = settings.getCustomSettings(GroovyCodeStyleSettings.class);
final GroovyBlock block = new GroovySimpleBlock(astNode, null, Indent.getAbsoluteNoneIndent(), null, groovySettings, customSettings,
CollectionFactory.<PsiElement, Alignment>hashMap(),
CollectionFactory.<PsiElement, GroovyBlock>hashMap());
final Map<PsiElement, Alignment> innerAlignments = CollectionFactory.hashMap();
if (customSettings.USE_FLYING_GEESE_BRACES) {
element.accept(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (GeeseUtil.isClosureRBrace(element)) {
final Alignment alignment = GeeseUtil.calculateRBraceAlignment(element, innerAlignments);
innerAlignments.put(element, alignment);
}
else {
super.visitElement(element);
}
}
});
}
final GroovyBlock block =
new GroovyBlock(astNode, null, Indent.getAbsoluteNoneIndent(), null, groovySettings, customSettings, innerAlignments);
return new GroovyFormattingModel(containingFile, block, FormattingDocumentModelImpl.createOn(containingFile));
}
@@ -1,43 +0,0 @@
/*
* Copyright 2000-2011 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.plugins.groovy.formatter;
import com.intellij.formatting.Alignment;
import com.intellij.formatting.Indent;
import com.intellij.formatting.Wrap;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
/**
* @author Max Medvedev
*/
public class GroovySimpleBlock extends GroovyBlock {
public GroovySimpleBlock(@NotNull ASTNode node,
@Nullable Alignment alignment,
@NotNull Indent indent,
@Nullable Wrap wrap,
CommonCodeStyleSettings settings,
GroovyCodeStyleSettings groovySettings,
@NotNull Map<PsiElement, Alignment> innerAlignments, Map<PsiElement, GroovyBlock> blocks) {
super(node, alignment, indent, wrap, settings, groovySettings, innerAlignments, blocks);
mySubBlocks = new GroovyBlockGenerator(this).generateSubBlocks();
}
}
@@ -33,36 +33,48 @@ import java.util.Map;
* @author peter
*/
public class MethodCallWithoutQualifierBlock extends GroovyBlock {
private final TextRange myRange;
private final PsiElement myNameElement;
private final boolean myTopLevel;
private final List<ASTNode> myChildren;
private final PsiElement myElem;
protected MethodCallWithoutQualifierBlock(PsiElement nameElement,
Alignment alignment,
Wrap wrap,
CommonCodeStyleSettings settings,
GroovyCodeStyleSettings groovySettings,
boolean topLevel,
List<ASTNode> children,
PsiElement elem,
Map<PsiElement, Alignment> innerAlignments, Map<PsiElement, GroovyBlock> blocks) {
super(nameElement.getNode(), alignment, Indent.getContinuationWithoutFirstIndent(), wrap, settings, groovySettings, innerAlignments,blocks);
myRange = new TextRange(nameElement.getTextRange().getStartOffset(), elem.getTextRange().getEndOffset());
public MethodCallWithoutQualifierBlock(PsiElement nameElement,
Alignment alignment,
Wrap wrap,
CommonCodeStyleSettings settings,
GroovyCodeStyleSettings groovySettings,
boolean topLevel,
List<ASTNode> children,
PsiElement elem,
Map<PsiElement, Alignment> innerAlignments) {
super(nameElement.getNode(), alignment, Indent.getContinuationWithoutFirstIndent(), wrap, settings, groovySettings, innerAlignments);
myNameElement = nameElement;
myTopLevel = topLevel;
myChildren = children;
myElem = elem;
}
mySubBlocks = new ArrayList<Block>();
final GroovySimpleBlock first =
new GroovySimpleBlock(nameElement.getNode(), myInnerAlignments.get(nameElement), Indent.getContinuationWithoutFirstIndent(), myWrap,
mySettings, myGroovySettings, myInnerAlignments, myBlocks);
mySubBlocks.add(first);
new GroovyBlockGenerator(this).addNestedChildrenSuffix(mySubBlocks, myAlignment, topLevel, children, children.size());
@NotNull
@Override
public List<Block> getSubBlocks() {
if (mySubBlocks == null) {
mySubBlocks = new ArrayList<Block>();
mySubBlocks.add(
new GroovyBlock(myNameElement.getNode(), myInnerAlignments.get(myNameElement), Indent.getContinuationWithoutFirstIndent(), myWrap,
mySettings, myGroovySettings, myInnerAlignments));
new GroovyBlockGenerator(this).addNestedChildrenSuffix(mySubBlocks, myAlignment, myTopLevel, myChildren, myChildren.size());
}
return mySubBlocks;
}
@NotNull
@Override
public TextRange getTextRange() {
return myRange;
return new TextRange(myNameElement.getTextRange().getStartOffset(), myElem.getTextRange().getEndOffset());
}
@Override
public boolean isLeaf() {
return false;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -663,9 +663,6 @@ mGSTRING_LITERAL = \"\"
{mGSTRING_LITERAL} { return mGSTRING_LITERAL; }
"$""/" { yypushback(2);
yybegin(WAIT_FOR_REGEX); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////// keywords /////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -738,13 +735,22 @@ mGSTRING_LITERAL = \"\"
"?" { yybegin(WAIT_FOR_REGEX);
return(mQUESTION); }
"/" { if (zzStartRead == 0 ||
zzBuffer.subSequence(0, zzStartRead).toString().trim().length() == 0) {
yypushback(1);
yybegin(WAIT_FOR_REGEX);
zzBuffer.subSequence(0, zzStartRead).toString().trim().length() == 0) {
yypushback(1);
yybegin(WAIT_FOR_REGEX);
} else {
return(mDIV);
}
}
"$""/" { if (zzStartRead == 0 ||
zzBuffer.subSequence(0, zzStartRead).toString().trim().length() == 0) {
yypushback(2);
yybegin(WAIT_FOR_REGEX);
} else {
yypushback(1);
return(mDOLLAR);
}
}
"/=" { yybegin(WAIT_FOR_REGEX);
return(mDIV_ASSIGN); }
"(" { yybegin(WAIT_FOR_REGEX);
@@ -35,6 +35,70 @@ public class GrStringUtil {
private GrStringUtil() {
}
public static String escapeForSlashyStrings(String str) {
final StringBuilder buffer = new StringBuilder(str.length());
escapeSymbolsForSlashyStrings(buffer, str);
return buffer.toString();
}
public static void escapeSymbolsForSlashyStrings(StringBuilder buffer, String str) {
final int length = str.length();
for (int idx = 0; idx < length; idx++) {
char ch = str.charAt(idx);
switch (ch) {
case '/':
buffer.append("\\/");
break;
default:
if (Character.isISOControl(ch) || ch == '$') {
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
}
}
}
}
public static String escapeSymbolsForDollarSlashyStrings(String str) {
final StringBuilder buffer = new StringBuilder(str.length());
escapeSymbolsForDollarSlashyStrings(buffer, str);
return buffer.toString();
}
public static void escapeSymbolsForDollarSlashyStrings(StringBuilder buffer, String str) {
final int length = str.length();
for (int idx = 0; idx < length; idx++) {
char ch = str.charAt(idx);
switch (ch) {
case '/':
if (idx + 1 < length && str.charAt(idx + 1) == '$') {
appendUnicode(buffer, '/');
appendUnicode(buffer, '$');
break;
}
default:
if (Character.isISOControl(ch)) {
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
}
}
}
}
private static void appendUnicode(StringBuilder buffer, char ch) {
String hexCode = Integer.toHexString(ch).toUpperCase();
buffer.append("\\u");
int paddingCount = 4 - hexCode.length();
while (paddingCount-- > 0) {
buffer.append(0);
}
buffer.append(hexCode);
}
public static String escapeSymbolsForGString(String s, boolean escapeDoubleQuotes) {
return escapeSymbolsForGString(s, escapeDoubleQuotes, false);
}
@@ -115,13 +179,7 @@ public class GrStringUtil {
buffer.append("\\").append(ch);
}
else if (Character.isISOControl(ch)) {
String hexCode = Integer.toHexString(ch).toUpperCase();
buffer.append("\\u");
int paddingCount = 4 - hexCode.length();
while (paddingCount-- > 0) {
buffer.append(0);
}
buffer.append(hexCode);
appendUnicode(buffer, ch);
}
else {
buffer.append(ch);
@@ -16,55 +16,38 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.AbstractElementManipulator;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
public class GroovyStringLiteralManipulator extends AbstractElementManipulator<GrLiteral> {
public GrLiteral handleContentChange(GrLiteral expr, TextRange range, String newContent) throws IncorrectOperationException {
public class GroovyStringLiteralManipulator extends AbstractElementManipulator<GrLiteralImpl> {
public GrLiteralImpl handleContentChange(GrLiteralImpl expr, TextRange range, String newContent) throws IncorrectOperationException {
if (!(expr.getValue() instanceof String)) throw new IncorrectOperationException("cannot handle content change");
String oldText = expr.getText();
if (oldText.startsWith("'")) {
newContent = GrStringUtil.escapeSymbolsForString(newContent, !oldText.startsWith("'''"), true);
}
else if (oldText.startsWith("\"")) {
newContent = GrStringUtil.escapeSymbolsForGString(newContent, !oldText.startsWith("\"\"\""), true);
}
else if (oldText.startsWith("/")) {
newContent = StringUtil.escapeSlashes(newContent);
}
//if there is $/-string we don't need to escape something
final String quote = GrStringUtil.getStartQuote(oldText);
String newText;
if (range.getStartOffset() == 1 && (newContent.indexOf('\n') >= 0 || newContent.indexOf('\r') >= 0)) {
String corner = oldText.substring(0, 1) + oldText.substring(0, 1) + oldText.substring(0, 1);
newText = corner + newContent + corner;
if (quote.startsWith("'")) {
newContent = GrStringUtil.escapeSymbolsForString(newContent, !quote.equals("'''"), false);
}
else {
newText = oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset());
else if (quote.startsWith("\"")) {
newContent = GrStringUtil.escapeSymbolsForGString(newContent, !quote.equals("\"\"\""), true);
}
else if ("/".equals(quote)) {
newContent = GrStringUtil.escapeForSlashyStrings(newContent);
}
else if ("$/".equals(quote)) {
newContent = GrStringUtil.escapeSymbolsForDollarSlashyStrings(newContent);
}
final GrExpression newExpr = GroovyPsiElementFactory.getInstance(expr.getProject()).createExpressionFromText(newText);
PsiElement firstChild = expr.getFirstChild();
assert firstChild != null && firstChild.getNextSibling() == null;
PsiElement newElement = newExpr.getFirstChild();
assert newElement != null;
firstChild.replace(newElement);
return expr;
String newText = oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset());
return expr.updateText(newText);
}
public TextRange getRangeInElement(final GrLiteral element) {
public TextRange getRangeInElement(final GrLiteralImpl element) {
final String text = element.getText();
if (element instanceof GrLiteralImpl && !(element.getValue() instanceof String)) {
if (!(element.getValue() instanceof String)) {
return super.getRangeInElement(element);
}
return getLiteralRange(text);
@@ -179,6 +179,10 @@ public class ExpressionsParsingTest extends GroovyParsingTestCase {
public void testregex$dollarSlashy3() throws Throwable { doTest(); }
public void testregex$dollarSlashy4() throws Throwable { doTest(); }
public void testregex$dollarSlashy5() throws Throwable { doTest(); }
public void testregex$dollarSlashy6() throws Throwable { doTest(); }
public void testregex$dollarSlashy7() throws Throwable { doTest(); }
public void testregex$dollarSlashy8() throws Throwable { doTest(); }
public void testregex$dollarSlashy9() throws Throwable { doTest(); }
public void testregex$dollarSlashyCode() throws Throwable { doTest(); }
public void testregex$dollarSlashyCodeUnfinished() throws Throwable { doTest(); }
public void testregex$dollarSlashyEof() throws Throwable { doTest(); }
@@ -1,2 +1,2 @@
print <error descr="Dollar-slashy strings cannot be the first argument of a command method call">$/abc/$</error>
print <error descr="Dollar-slashy strings cannot be the first argument of a command method call">$/a$bc/$</error>
print <error descr="';' or new line expected">$/abc/$</error>
print <error descr="';' or new line expected">$/a$bc/$</error>
@@ -0,0 +1,8 @@
$/abc/$
-----
Groovy script
Literal
GroovyASTPsiElementImpl($/ regex literal)
PsiElement($/ regex begin)('$/')
PsiElement($/ regex content)('abc')
PsiElement($/ regex end)('/$')
@@ -0,0 +1,12 @@
print $/abc/$
-----
Groovy script
Reference expression
PsiElement(identifier)('print')
PsiWhiteSpace(' ')
PsiErrorElement:';' or new line expected
PsiElement($)('$')
PsiElement(/)('/')
PsiElement(identifier)('abc')
PsiElement(/)('/')
PsiElement(identifier)('$')
@@ -0,0 +1,14 @@
print($/abc/$)
-----
Groovy script
Method call
Reference expression
PsiElement(identifier)('print')
Arguments
PsiElement(()('(')
Literal
GroovyASTPsiElementImpl($/ regex literal)
PsiElement($/ regex begin)('$/')
PsiElement($/ regex content)('abc')
PsiElement($/ regex end)('/$')
PsiElement())(')')
@@ -0,0 +1,17 @@
print a, $/a/$
-----
Groovy script
Call expression
Reference expression
PsiElement(identifier)('print')
PsiWhiteSpace(' ')
Command arguments
Reference expression
PsiElement(identifier)('a')
PsiElement(,)(',')
PsiWhiteSpace(' ')
Literal
GroovyASTPsiElementImpl($/ regex literal)
PsiElement($/ regex begin)('$/')
PsiElement($/ regex content)('a')
PsiElement($/ regex end)('/$')