Merge remote-tracking branch 'origin/master'
authorAlexander Lobas <Alexander.Lobas@jetbrains.com>
Tue, 31 Jan 2012 08:22:25 +0000 (12:22 +0400)
committerAlexander Lobas <Alexander.Lobas@jetbrains.com>
Tue, 31 Jan 2012 08:22:25 +0000 (12:22 +0400)
platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java [new file with mode: 0644]
platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfigurable.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfiguration.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.form [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java [new file with mode: 0644]
platform/platform-resources/src/META-INF/LangExtensionPoints.xml
platform/platform-resources/src/META-INF/LangExtensions.xml

diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
new file mode 100644 (file)
index 0000000..e6803f5
--- /dev/null
@@ -0,0 +1,191 @@
+package com.intellij.lang.folding;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.Stack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Builds custom folding regions. If custom folding is supported for a language, its FoldingBuilder must be inherited from this class.
+ * 
+ * @author Rustam Vishnyakov
+ */
+public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements DumbAware {
+
+  private CustomFoldingProvider myDefaultProvider;
+
+  @NotNull
+  @Override
+  public final FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) {
+    List<FoldingDescriptor> descriptors = new ArrayList<FoldingDescriptor>();
+    if (CustomFoldingProvider.getAllProviders().length > 0) {
+      myDefaultProvider = null;
+      addCustomFoldingRegionsRecursively(root.getNode(), descriptors);
+    }
+    buildLanguageFoldRegions(descriptors, root, document, quick);
+    return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
+  }
+
+  @NotNull
+  @Override
+  public final FoldingDescriptor[] buildFoldRegions(@NotNull ASTNode node, @NotNull Document document) {
+    return buildFoldRegions(node.getPsi(), document, false);
+  }
+
+  /**
+   * Implement this method to build language folding regions besides custom folding regions.
+   *
+   * @param descriptors The list of folding descriptors to store results to.
+   * @param root        The root node for which the folding is requested.
+   * @param document    The document for which folding is built.
+   * @param quick       whether the result should be provided as soon as possible without reference resolving
+   *                    and complex checks.
+   */
+  protected abstract void buildLanguageFoldRegions(@NotNull List<FoldingDescriptor> descriptors,
+                                                   @NotNull PsiElement root,
+                                                   @NotNull Document document,
+                                                   boolean quick);
+  
+  private void addCustomFoldingRegionsRecursively(@NotNull ASTNode node, List<FoldingDescriptor> descriptors) {
+    Stack<ASTNode> customFoldingNodesStack = new Stack<ASTNode>(1);
+    for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) {
+      if (isCustomRegionStart(child)) {
+        customFoldingNodesStack.push(child);
+      }
+      else if (isCustomRegionEnd(child)) {
+        if (!customFoldingNodesStack.isEmpty()) {
+          ASTNode startNode = customFoldingNodesStack.pop();
+          int startOffset = startNode.getTextRange().getStartOffset();
+          TextRange range = new TextRange(startOffset, child.getTextRange().getEndOffset());
+          descriptors.add(new FoldingDescriptor(node, range));
+        }
+      }
+      else {
+        addCustomFoldingRegionsRecursively(child, descriptors);
+      }
+    }
+  }
+
+  @Override
+  public final String getPlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
+    if (mayContainCustomFoldings(node)) {
+      PsiFile file = node.getPsi().getContainingFile();
+      PsiElement contextElement = file.findElementAt(range.getStartOffset());
+      if (contextElement != null && isCustomFoldingCandidate(contextElement.getNode())) {
+        String elementText = contextElement.getText();
+        CustomFoldingProvider defaultProvider = getDefaultProvider(elementText);
+        if (defaultProvider != null && defaultProvider.isCustomRegionStart(elementText)) {
+          return defaultProvider.getPlaceholderText(elementText);
+        }
+      }
+    }
+    return getLanguagePlaceholderText(node, range);
+  }
+  
+  protected abstract String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range);
+
+
+  @Override
+  public final String getPlaceholderText(@NotNull ASTNode node) {
+    return "...";
+  }
+
+
+  @Override
+  public final boolean isCollapsedByDefault(@NotNull ASTNode node) {
+    // TODO<rv>: Modify Folding API and pass here folding range.
+    if (mayContainCustomFoldings(node)) {
+      for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) {
+        if (isCustomRegionStart(child)) {
+          String childText = child.getText();
+          CustomFoldingProvider defaultProvider = getDefaultProvider(childText);
+          return defaultProvider != null && defaultProvider.isCollapsedByDefault(childText);
+        }
+      }
+    }
+    return isRegionCollapsedByDefault(node);
+  }
+
+  /**
+   * Returns the default collapsed state for the folding region related to the specified node.
+   *
+   * @param node the node for which the collapsed state is requested.
+   * @return true if the region is collapsed by default, false otherwise.
+   */
+  protected abstract boolean isRegionCollapsedByDefault(@NotNull ASTNode node);
+
+  /**
+   * Returns true if the node corresponds to custom region start. The node must be a custom folding candidate and match custom folding 
+   * start pattern.
+   *
+   * @param node The node which may contain custom region start.
+   * @return True if the node marks a custom region start.
+   */
+  protected final boolean isCustomRegionStart(ASTNode node) {
+    if (isCustomFoldingCandidate(node)) {
+      String nodeText = node.getText();
+      CustomFoldingProvider defaultProvider = getDefaultProvider(nodeText);
+      return defaultProvider != null && defaultProvider.isCustomRegionStart(nodeText);
+    }
+    return false;
+  }
+
+  /**
+   * Returns true if the node corresponds to custom region end. The node must be a custom folding candidate and match custom folding
+   * end pattern.
+   *
+   * @param node The node which may contain custom region end
+   * @return True if the node marks a custom region end.
+   */
+  protected final boolean isCustomRegionEnd(ASTNode node) {
+    if (isCustomFoldingCandidate(node)) {
+      String nodeText = node.getText();
+      CustomFoldingProvider defaultProvider = getDefaultProvider(nodeText);
+      return defaultProvider != null && defaultProvider.isCustomRegionEnd(nodeText);
+    }
+    return false;
+  }
+
+  @Nullable
+  private CustomFoldingProvider getDefaultProvider(String elementText) {
+    if (myDefaultProvider == null) {
+      for (CustomFoldingProvider provider : CustomFoldingProvider.getAllProviders()) {
+        if (provider.isCustomRegionStart(elementText) || provider.isCustomRegionEnd(elementText)) {
+          myDefaultProvider = provider;
+        }
+      }
+    }
+    return myDefaultProvider;
+  }
+
+  /**
+   * Checks if a node may contain custom folding tags. By default returns true for PsiComment but a language folding builder may override
+   * this method to allow only specific subtypes of comments (for example, line comments only).
+   * @param node The node to check.
+   * @return True if the node may contain custom folding tags.
+   */
+  protected boolean isCustomFoldingCandidate(ASTNode node) {
+    return node.getPsi() instanceof PsiComment;
+  }
+
+  /**
+   * Returns true if the node may contain custom foldings in its immediate child nodes. By default any node will be checked for custom
+   * foldings but for performance reasons it makes sense to override this method to check only the nodes which actually may contain
+   * custom folding nodes (for example, group statements).
+   *
+   * @param node  The node to check.
+   * @return      True if the node may contain custom folding nodes (true by default).
+   */
+  protected boolean mayContainCustomFoldings(ASTNode node) {
+    return true;
+  }
+}
diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingProvider.java
new file mode 100644 (file)
index 0000000..4086abd
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2012 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.lang.folding;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+
+import java.util.List;
+
+/**
+ * Base class and extension point for custom folding providers.
+ *
+ * @author Rustam Vishnyakov
+ */
+public abstract class CustomFoldingProvider {
+  public static final ExtensionPointName<CustomFoldingProvider> EP_NAME = ExtensionPointName.create("com.intellij.customFoldingProvider");
+
+  public static CustomFoldingProvider[] getAllProviders() {
+    return Extensions.getExtensions(EP_NAME);
+  }
+
+  public abstract boolean isCustomRegionStart(String elementText);
+  public abstract boolean isCustomRegionEnd(String elementText);
+  public abstract String getPlaceholderText(String elementText);
+  
+  public boolean isCollapsedByDefault(String text) {
+    return false;
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfigurable.java b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfigurable.java
new file mode 100644 (file)
index 0000000..b35737c
--- /dev/null
@@ -0,0 +1,83 @@
+package com.intellij.lang.customFolding;
+
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author Rustam Vishnyakov
+ */
+public class CustomFoldingConfigurable implements SearchableConfigurable {
+
+  private CustomFoldingConfiguration myConfiguration;
+  private CustomFoldingSettingsPanel mySettingsPanel;
+
+  public CustomFoldingConfigurable(Project project) {
+    myConfiguration = CustomFoldingConfiguration.getInstance(project);
+    mySettingsPanel = new CustomFoldingSettingsPanel();
+  }
+
+  @NotNull
+  @Override
+  public String getId() {
+    return getDisplayName();
+  }
+
+  @Override
+  public Runnable enableSearch(String option) {
+    return null;
+  }
+
+  @Nls
+  @Override
+  public String getDisplayName() {
+    return "Custom Folding"; //TODO<rv> Move to resources
+  }
+
+  @Override
+  public Icon getIcon() {
+    return null;
+  }
+
+  @Override
+  public String getHelpTopic() {
+    return null; //TODO<rv>: Define help topic
+  }
+
+  @Override
+  public JComponent createComponent() {
+    return mySettingsPanel.getComponent();
+  }
+
+  @Override
+  public boolean isModified() {
+    return myConfiguration.getState().isEnabled() != mySettingsPanel.isEnabled() ||
+           !myConfiguration.getState().getStartFoldingPattern().equals(mySettingsPanel.getStartPattern()) ||
+           !myConfiguration.getState().getEndFoldingPattern().equals(mySettingsPanel.getEndPattern()) ||
+           !myConfiguration.getState().getDefaultCollapsedStatePattern().equals(mySettingsPanel.getCollapsedStatePattern());
+  }
+
+  @Override
+  public void apply() throws ConfigurationException {
+    myConfiguration.getState().setStartFoldingPattern(mySettingsPanel.getStartPattern());
+    myConfiguration.getState().setEndFoldingPattern(mySettingsPanel.getEndPattern());
+    myConfiguration.getState().setEnabled(mySettingsPanel.isEnabled());
+    myConfiguration.getState().setDefaultCollapsedStatePattern(mySettingsPanel.getCollapsedStatePattern());
+  }
+
+  @Override
+  public void reset() {
+    mySettingsPanel.setStartPattern(myConfiguration.getState().getStartFoldingPattern());
+    mySettingsPanel.setEndPattern(myConfiguration.getState().getEndFoldingPattern());
+    mySettingsPanel.setEnabled(myConfiguration.getState().isEnabled());
+    mySettingsPanel.setCollapsedStatePattern(myConfiguration.getState().getDefaultCollapsedStatePattern());
+  }
+
+  @Override
+  public void disposeUIResources() {
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfiguration.java b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingConfiguration.java
new file mode 100644 (file)
index 0000000..78a88b6
--- /dev/null
@@ -0,0 +1,72 @@
+package com.intellij.lang.customFolding;
+
+import com.intellij.openapi.components.*;
+import com.intellij.openapi.project.Project;
+
+/**
+ * @author Rustam Vishnyakov
+ */
+@State(
+    name = "CustomFolding",
+    storages = {
+        @Storage( file = "$PROJECT_FILE$"),
+        @Storage( file = "$PROJECT_CONFIG_DIR$/customFolding.xml", scheme = StorageScheme.DIRECTORY_BASED)
+})
+public class CustomFoldingConfiguration implements PersistentStateComponent<CustomFoldingConfiguration.State> {
+  
+  private State myState = new State();
+  
+  public static CustomFoldingConfiguration getInstance(Project project) {
+    return ServiceManager.getService(project, CustomFoldingConfiguration.class);
+  }
+
+  @Override
+  public State getState() {
+    return myState;
+  }
+
+  @Override
+  public void loadState(State state) {
+    myState = state;
+  }
+
+  public static class State {
+
+    private String startFoldingPattern = "";
+    private String endFoldingPattern = "";
+    private String defaultCollapsedStatePattern = "";
+    private boolean isEnabled = false;
+
+    public String getDefaultCollapsedStatePattern() {
+      return defaultCollapsedStatePattern;
+    }
+
+    public void setDefaultCollapsedStatePattern(String defaultCollapsedStatePattern) {
+      this.defaultCollapsedStatePattern = defaultCollapsedStatePattern == null ? "" : defaultCollapsedStatePattern.trim();
+    }
+
+    public String getStartFoldingPattern() {
+      return startFoldingPattern;
+    }
+
+    public void setStartFoldingPattern(String startFoldingPattern) {
+      this.startFoldingPattern = startFoldingPattern == null ? "" : startFoldingPattern.trim();
+    }
+
+    public String getEndFoldingPattern() {
+      return endFoldingPattern;
+    }
+
+    public void setEndFoldingPattern(String endFoldingPattern) {
+      this.endFoldingPattern = endFoldingPattern == null ? "" : endFoldingPattern.trim();
+    }
+
+    public boolean isEnabled() {
+      return isEnabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+      isEnabled = enabled;
+    }
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.form b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.form
new file mode 100644 (file)
index 0000000..cc0911d
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.lang.customFolding.CustomFoldingSettingsPanel">
+  <grid id="27dc6" binding="mySettingsPanel" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="500" height="400"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="58b9a" class="javax.swing.JTextField" binding="myFoldingStartField">
+        <constraints>
+          <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="1829f" class="com.intellij.ui.components.JBLabel">
+        <constraints>
+          <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Folding start pattern:"/>
+        </properties>
+      </component>
+      <component id="aadcd" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Folding end pattern:"/>
+        </properties>
+      </component>
+      <component id="6fcc1" class="javax.swing.JTextField" binding="myFoldingEndField">
+        <constraints>
+          <grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="70f30" class="com.intellij.ui.components.JBCheckBox" binding="myEnabledBox">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="9c33b" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="0" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Enable custom code folding"/>
+        </properties>
+      </component>
+      <component id="ecb20" class="javax.swing.JTextField" binding="myCollapsedStateField">
+        <constraints>
+          <grid row="3" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+            <preferred-size width="150" height="-1"/>
+          </grid>
+        </constraints>
+        <properties/>
+      </component>
+      <component id="530c4" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Default collapsed state pattern:"/>
+        </properties>
+      </component>
+      <vspacer id="8d1b3">
+        <constraints>
+          <grid row="5" column="2" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <grid id="1f466" binding="myPredefinedPatternsPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="4" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none" title="Predefined patterns:">
+          <font/>
+        </border>
+        <children>
+          <component id="33207" class="javax.swing.JRadioButton" binding="myVisualStudioRadioButton" default-binding="true">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="Visual Studio"/>
+            </properties>
+          </component>
+          <component id="bffa3" class="javax.swing.JRadioButton" binding="myNetBeansRadioButton" default-binding="true">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="NetBeans"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+    </children>
+  </grid>
+</form>
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.java b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingSettingsPanel.java
new file mode 100644 (file)
index 0000000..17bd1aa
--- /dev/null
@@ -0,0 +1,100 @@
+package com.intellij.lang.customFolding;
+
+import com.intellij.ui.components.JBCheckBox;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * @author Rustam Vishnyakov
+ */
+public class CustomFoldingSettingsPanel {
+  private JPanel mySettingsPanel;
+  private JTextField myFoldingStartField;
+  private JTextField myFoldingEndField;
+  private JBCheckBox myEnabledBox;
+  private JTextField myCollapsedStateField;
+  private JRadioButton myVisualStudioRadioButton;
+  private JRadioButton myNetBeansRadioButton;
+  private JPanel myPredefinedPatternsPanel;
+
+  public CustomFoldingSettingsPanel() {
+    myEnabledBox.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        boolean isEnabled = myEnabledBox.isSelected();
+        setFieldsEnabled(isEnabled);
+      }
+    });
+    ButtonGroup predefinedSettingsGroup = new ButtonGroup();
+    predefinedSettingsGroup.add(myNetBeansRadioButton);
+    predefinedSettingsGroup.add(myVisualStudioRadioButton);
+    myVisualStudioRadioButton.setSelected(false);
+    myNetBeansRadioButton.setSelected(false);
+    
+    myNetBeansRadioButton.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        myFoldingStartField.setText(".*<editor-fold .*desc=\"(.*)\".*$");
+        myFoldingEndField.setText(".*</editor-fold>");
+        myCollapsedStateField.setText("defaultstate=\"collapsed\"");
+      }
+    });
+
+    myVisualStudioRadioButton.addActionListener(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        myFoldingStartField.setText(".*region (.*)$");
+        myFoldingEndField.setText(".*endregion");
+        myCollapsedStateField.setText("");
+      }
+    });
+  }
+
+  public JComponent getComponent() {
+    return mySettingsPanel;
+  }
+  
+  public String getStartPattern() {
+    return myFoldingStartField.getText();
+  }
+  
+  public String getEndPattern() {
+    return myFoldingEndField.getText();
+  }
+  
+  public void setStartPattern(String startPattern) {
+    myFoldingStartField.setText(startPattern);
+  }
+  
+  public void setEndPattern(String endPattern) {
+    myFoldingEndField.setText(endPattern);
+  }
+  
+  public void setEnabled(boolean enabled) {
+    myEnabledBox.setSelected(enabled);
+    setFieldsEnabled(enabled);
+  }
+  
+  public boolean isEnabled() {
+    return myEnabledBox.isSelected();
+  }
+  
+  public void setCollapsedStatePattern(String pattern) {
+    myCollapsedStateField.setText(pattern);
+  }
+  
+  public String getCollapsedStatePattern() {
+    return myCollapsedStateField.getText();
+  }
+
+  private void setFieldsEnabled(boolean enabled) {
+    myFoldingStartField.setEnabled(enabled);
+    myFoldingEndField.setEnabled(enabled);
+    myCollapsedStateField.setEnabled(enabled);
+    myPredefinedPatternsPanel.setEnabled(enabled);
+    myNetBeansRadioButton.setEnabled(enabled);
+    myVisualStudioRadioButton.setEnabled(enabled);
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java b/platform/lang-impl/src/com/intellij/lang/customFolding/NetBeansCustomFoldingProvider.java
new file mode 100644 (file)
index 0000000..feef6f0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2012 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.lang.customFolding;
+
+import com.intellij.lang.folding.CustomFoldingProvider;
+
+/**
+ * Custom folding provider for <a href="http://ui.netbeans.org/docs/ui/code_folding/cf_uispec.html#menus">NetBeans folding conventions.</a>
+ * @author Rustam Vishnyakov
+ */
+public class NetBeansCustomFoldingProvider extends CustomFoldingProvider {
+  @Override
+  public boolean isCustomRegionStart(String elementText) {
+    return elementText.contains("<editor-fold");
+  }
+
+  @Override
+  public boolean isCustomRegionEnd(String elementText) {
+    return elementText.contains("</editor-fold");
+  }
+
+  @Override
+  public String getPlaceholderText(String elementText) {
+    String customText = elementText.replaceFirst(".*desc\\s*=\\s*\"(.*)\".*", "$1").trim();
+    return customText.isEmpty() ? "..." : customText;
+  }
+
+  @Override
+  public boolean isCollapsedByDefault(String text) {
+    return text.matches(".*defaultstate\\s*=\\s*\"collapsed\".*");
+  }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java b/platform/lang-impl/src/com/intellij/lang/customFolding/VisualStudioCustomFoldingProvider.java
new file mode 100644 (file)
index 0000000..784e9a6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2012 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.lang.customFolding;
+
+import com.intellij.lang.folding.CustomFoldingProvider;
+
+/**
+ * Supports <a href="http://msdn.microsoft.com/en-us/library/9a1ybwek%28v=vs.100%29.aspx">VisualStudio custom foldings.</a>
+ * @author Rustam Vishnyakov
+ */
+public class VisualStudioCustomFoldingProvider extends CustomFoldingProvider {
+  @Override
+  public boolean isCustomRegionStart(String elementText) {
+    return elementText.contains("region") && elementText.matches("..?\\s*region.*");
+  }
+
+  @Override
+  public boolean isCustomRegionEnd(String elementText) {
+    return elementText.contains("endregion");
+  }
+
+  @Override
+  public String getPlaceholderText(String elementText) {
+    return elementText.replaceFirst("..?\\s*region(.*)","$1").trim();
+  }
+
+}
index 044b1b5cac10f74d9864d14edd86ad407da8b79f..6d199ff55fb932f8bf2292566b0e4937b96a88c6 100644 (file)
   <extensionPoint name="lang.braceMatcher"
                   beanClass="com.intellij.lang.LanguageExtensionPoint"/>
   <extensionPoint name="lang.foldingBuilder"
-                  beanClass="com.intellij.lang.LanguageExtensionPoint"/>                  
+                  beanClass="com.intellij.lang.LanguageExtensionPoint"/>
+  <extensionPoint name="customFoldingProvider"
+                  interface="com.intellij.lang.folding.CustomFoldingProvider"/>
   <extensionPoint name="lang.psiStructureViewFactory"
                   beanClass="com.intellij.lang.LanguageExtensionPoint"/>
   <extensionPoint name="lang.structureViewExtension"
index c5d4161b65adf12fc3b7ed31796992d7a5732248..2d36ef88f549f331fbe423becaf0fde695f4cd9a 100644 (file)
 
   <projectService serviceInterface="com.intellij.openapi.module.ModulePointerManager"
                   serviceImplementation="com.intellij.openapi.module.impl.ModulePointerManagerImpl"/>
+
+  <customFoldingProvider implementation="com.intellij.lang.customFolding.NetBeansCustomFoldingProvider"/>
+  <customFoldingProvider implementation="com.intellij.lang.customFolding.VisualStudioCustomFoldingProvider"/>
 </extensions>