PY-11855 Run manage.py task improvements
authorIlya.Kazakevich <Ilya.Kazakevich@jetbrains.com>
Thu, 13 Nov 2014 19:45:14 +0000 (22:45 +0300)
committerIlya.Kazakevich <Ilya.Kazakevich@jetbrains.com>
Thu, 13 Nov 2014 19:45:14 +0000 (22:45 +0300)
History added (but not folded yet)

platform/core-api/src/com/intellij/ide/util/PropertiesComponent.java
platform/core-impl/src/com/intellij/ide/util/PropertiesComponentImpl.java
python/src/com/jetbrains/python/commandInterface/commandsWithArgs/CommandExecutionInfo.java [new file with mode: 0644]
python/src/com/jetbrains/python/commandInterface/commandsWithArgs/CommandInterfacePresenterCommandBased.java
python/src/com/jetbrains/python/commandInterface/commandsWithArgs/InCommandStrategy.java
python/src/com/jetbrains/python/commandInterface/commandsWithArgs/NoCommandStrategy.java
python/src/com/jetbrains/python/commandInterface/commandsWithArgs/Strategy.java
python/src/com/jetbrains/python/suggestionList/SuggestionList.java
python/src/com/jetbrains/python/suggestionList/SuggestionsBuilder.java

index f733cd04f4a64005c7edc3d0ee01a66a1fce8ecf..c97bab4d16a157e30828018e3a67f8b9d97f116a 100644 (file)
@@ -43,6 +43,7 @@ public abstract class PropertiesComponent {
    */
   public abstract void setValue(@NotNull String name, @NotNull String value, @NotNull String defaultValue);
 
+  @Nullable
   public abstract String[] getValues(@NonNls String name);
 
   public abstract void setValues(@NonNls String name, String[] values);
index a743569b17984de2436e51acd9a18d6d628e8e0f..3964076967486a5415200078aba8406e4f080986 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil;
 import org.jdom.Element;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -94,6 +95,7 @@ public class PropertiesComponentImpl extends PropertiesComponent implements Pers
     return myMap.containsKey(name);
   }
 
+  @Nullable
   @Override
   public String[] getValues(@NonNls String name) {
     final String value = getValue(name);
diff --git a/python/src/com/jetbrains/python/commandInterface/commandsWithArgs/CommandExecutionInfo.java b/python/src/com/jetbrains/python/commandInterface/commandsWithArgs/CommandExecutionInfo.java
new file mode 100644 (file)
index 0000000..b7e533b
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.commandInterface.commandsWithArgs;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Information about command and its arguments to save in history / pass to execution etc.
+ *
+ * @author Ilya.Kazakevich
+ */
+public class CommandExecutionInfo {
+  /**
+   * Command and arguments separator.
+   */
+  private static final String SEPARATOR = " ";
+  @NotNull
+  private final String myCommandName;
+  @NotNull
+  private final String[] myArguments;
+
+  /**
+   * @param commandName command
+   * @param arguments   its arguments
+   */
+  public CommandExecutionInfo(@NotNull final String commandName, @NotNull final String... arguments) {
+    myCommandName = commandName;
+    myArguments = arguments.clone();
+  }
+
+  /**
+   * @return command
+   */
+  @NotNull
+  public String getCommandName() {
+    return myCommandName;
+  }
+
+  /**
+   * @return command arguments
+   */
+  @NotNull
+  public String[] getArguments() {
+    return myArguments.clone();
+  }
+
+  /**
+   * @return command in format "command arg1 arg2". Opposite to {@link #fromString(String)}
+   * @see #fromString(String)
+   */
+  @NotNull
+  public String toString() {
+    // TODO: What if command or argument has space in it? Escape somehow!
+    return StringUtil.join(ArrayUtil.mergeArrays(new String[]{myCommandName}, myArguments), SEPARATOR);
+  }
+
+  /**
+   * @param stringToUnserialize string created by {@link #toString()}
+   * @return command parsed from string
+   * @see #toString()
+   */
+  @Nullable
+  public static CommandExecutionInfo fromString(@NotNull final String stringToUnserialize) {
+    // TODO: What if command or argument has space in it? Escape somehow!
+    final List<String> strings = StringUtil.split(stringToUnserialize, SEPARATOR);
+    if (strings.isEmpty()) {
+      return null;
+    }
+    return new CommandExecutionInfo(strings.get(0), ArrayUtil.toStringArray(strings.subList(1, strings.size())));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof CommandExecutionInfo)) return false;
+
+    CommandExecutionInfo info = (CommandExecutionInfo)o;
+
+    if (!Arrays.equals(myArguments, info.myArguments)) return false;
+    if (!myCommandName.equals(info.myCommandName)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = myCommandName.hashCode();
+    result = 31 * result + Arrays.hashCode(myArguments);
+    return result;
+  }
+}
index 19fec244278f4d566010a483c386ef06726f9443..702f4bb77fb17b1758b05fd8f1955912b8ee839f 100644 (file)
@@ -110,14 +110,56 @@ public class CommandInterfacePresenterCommandBased extends CommandInterfacePrese
     }
 
     if (!suggestionInfo.myShowOnlyWhenRequested && !suggestions.isEmpty()) {
+      final SuggestionsBuilder suggestionsBuilder = getBuilderWithHistory();
+      suggestionsBuilder.add(suggestions);
+
       myView
-        .displaySuggestions(new SuggestionsBuilder(suggestions, true), suggestionInfo.myAbsolute, null);
+        .displaySuggestions(suggestionsBuilder, suggestionInfo.myAbsolute, null);
     }
     else {
       myView.removeSuggestions();
     }
   }
 
+  /**
+   * @return builder that already has history in its prefix group (see {@link com.jetbrains.python.suggestionList.SuggestionsBuilder})
+   */
+  @NotNull
+  private SuggestionsBuilder getBuilderWithHistory() {
+    final SuggestionsBuilder suggestionsBuilder = new SuggestionsBuilder();
+    final List<CommandExecutionInfo> history = getHistory();
+    final Collection<String> historyCommands = new LinkedHashSet<String>();
+    for (final CommandExecutionInfo info : history) {
+      historyCommands.add(info.toString());
+    }
+
+    if (!historyCommands.isEmpty()) {
+      // TODO: Later implement folding by name
+      suggestionsBuilder.changeGroup(false);
+      suggestionsBuilder
+        .add(ArrayUtil.toStringArray(historyCommands));
+      suggestionsBuilder.changeGroup(true);
+    }
+
+    return suggestionsBuilder;
+  }
+
+  /**
+   * @return execution info from history. It is empty by default, child should implement it.
+   */
+  @NotNull
+  protected List<CommandExecutionInfo> getHistory() {
+    return Collections.emptyList();
+  }
+
+  /**
+   * @return command that entered in box, or null of just entered
+   */
+  @Nullable
+  protected CommandExecutionInfo getCommandToExecute() {
+    return myStrategy.getCommandToExecute();
+  }
+
   /**
    * Finds and sets appropriate strategy
    */
@@ -160,7 +202,9 @@ public class CommandInterfacePresenterCommandBased extends CommandInterfacePrese
     final SuggestionInfo suggestionInfo = myStrategy.getSuggestionInfo();
     final List<String> suggestions = suggestionInfo.getSuggestions();
     if (!suggestions.isEmpty()) {
-      myView.displaySuggestions(new SuggestionsBuilder(suggestions, true), suggestionInfo.myAbsolute, null);
+      final SuggestionsBuilder suggestionsBuilder = getBuilderWithHistory();
+      suggestionsBuilder.add(suggestions);
+      myView.displaySuggestions(suggestionsBuilder, suggestionInfo.myAbsolute, null);
     }
   }
 
index aa423a5f862432eeefc9a5852f76cca8228bbf32..de1dce0df232f58a10aafa00a2ac7a78da3b2b50 100644 (file)
@@ -15,7 +15,9 @@
  */
 package com.jetbrains.python.commandInterface.commandsWithArgs;
 
+import com.intellij.util.ArrayUtil;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -71,6 +73,12 @@ class InCommandStrategy extends Strategy {
     return ((lastPart != null) && !getSuggestionInfo().getSuggestions().contains(lastPart));
   }
 
+  @Nullable
+  @Override
+  CommandExecutionInfo getCommandToExecute() {
+    return new CommandExecutionInfo(myCommand.getName(), ArrayUtil.toStringArray(myArguments));
+  }
+
   @NotNull
   @Override
   ErrorInfo getShowErrorInfo() {
index e56ad60766b58af63f27a7a710971231891b26d6..d4da6eac1ef735888c63d44601578b0e2923af6c 100644 (file)
@@ -16,6 +16,7 @@
 package com.jetbrains.python.commandInterface.commandsWithArgs;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 
@@ -56,4 +57,10 @@ class NoCommandStrategy extends Strategy {
   private boolean isTextBoxEmpty() {
     return myPresenter.getView().getText().isEmpty();
   }
+
+  @Nullable
+  @Override
+  CommandExecutionInfo getCommandToExecute() {
+    return null;
+  }
 }
index 9e61d2c20f2ddd684d76d13a064684a1ddbec8cc..8801f57bd425a85a0e2c43a0302322049336615a 100644 (file)
@@ -16,6 +16,7 @@
 package com.jetbrains.python.commandInterface.commandsWithArgs;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -51,6 +52,13 @@ abstract class Strategy {
   abstract SuggestionInfo getSuggestionInfo();
 
 
+  /**
+   * @return command that entered in box, or null of just entered
+   */
+  @Nullable
+  abstract CommandExecutionInfo getCommandToExecute();
+
+
   /**
    * @return errors
    */
index ef799a5034fd5528a6938b69d8b2090e15bcaed7..8d200c01b439532a42602ff5d6af603a06108a21 100644 (file)
@@ -193,10 +193,10 @@ public class SuggestionList {
   private static class MyCellRenderer extends DefaultListCellRenderer {
     @NotNull
     private static final Color ODD_GROUP_SELECTED_BACKGROUND_COLOR =
-      EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTION_BACKGROUND_COLOR);
+      EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR);
     @NotNull
     private static final Color ODD_GROUP_BACKGROUND_COLOR =
-      EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND);
+      EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR);
 
     @Override
     public Component getListCellRendererComponent(final JList list,
@@ -212,6 +212,8 @@ public class SuggestionList {
 
       if (element.myOddGroup) {
         component.setBackground(isSelected ? ODD_GROUP_SELECTED_BACKGROUND_COLOR : ODD_GROUP_BACKGROUND_COLOR);
+        final Font oldFont = component.getFont();
+        component.setFont(new Font(oldFont.getName(), Font.ITALIC, oldFont.getSize()));
       }
 
       if (!(component instanceof JLabel)) {
index dbe3c6f867abcf6dfb71341bc7139c09b30950b7..8493f7b6316c416efdcc0786dd2f9afd6757fae5 100644 (file)
@@ -21,41 +21,43 @@ import java.util.*;
 
 /**
  * Builds list of suggestions.
+ * <p/>
  * You may create suggestions from words, you may add new groups and do other useful things.
  * It works like chain pattern, so it returns itself.
+ * <p/>
+ * Builder consists of 2 groups: prefix (first one) and main (second one) group.
+ * Each may be empty.
+ * Use {@link #changeGroup(boolean)} to switch between them
  *
  * @author Ilya.Kazakevich
  */
 public class SuggestionsBuilder {
+  private static final MySuggestionComparator SUGGESTION_COMPARATOR = new MySuggestionComparator();
   @NotNull
-  private final List<List<Suggestion>> myList = new ArrayList<List<Suggestion>>();
+  private final List<Suggestion> myPrefixGroup = new ArrayList<Suggestion>();
+  @NotNull
+  private final List<Suggestion> myMainGroup = new ArrayList<Suggestion>();
+  @NotNull
+  private List<Suggestion> myCurrentGroup = myMainGroup;
 
   public SuggestionsBuilder() {
-    myList.add(new ArrayList<Suggestion>());
+
   }
 
   /**
    * @param words list of words to add (to the first group)
-   * @param sort  sort passed words
    */
-  public SuggestionsBuilder(@NotNull List<String> words, final boolean sort) {
-    this();
-    if (sort) {
-      // No guarantee passed argument is mutable
-      //noinspection AssignmentToMethodParameter
-      words = new ArrayList<String>(words);
-      Collections.sort(words);
-    }
+  public SuggestionsBuilder(@NotNull final List<String> words) {
     add(words);
   }
 
   /**
-   * Creates next group and sets it as default
+   * Switches to the next group and sets it as default
+   *
+   * @param main use main group if true, prefix otherwise
    */
-  public SuggestionsBuilder nextGroup() {
-    if (!getCurrentGroup().isEmpty()) {
-      myList.add(new ArrayList<Suggestion>());
-    }
+  public SuggestionsBuilder changeGroup(final boolean main) {
+    myCurrentGroup = (main ? myMainGroup : myPrefixGroup);
     return this;
   }
 
@@ -81,27 +83,30 @@ public class SuggestionsBuilder {
    * @param strong strong or not
    */
   public SuggestionsBuilder add(@NotNull final String text, final boolean strong) {
-    getCurrentGroup().add(new Suggestion(text, strong));
+    myCurrentGroup.add(new Suggestion(text, strong));
+    Collections.sort(myCurrentGroup, SUGGESTION_COMPARATOR);
     return this;
   }
 
-  /**
-   * @return elements from current group
-   */
-  @NotNull
-  private List<Suggestion> getCurrentGroup() {
-    return myList.get(myList.size() - 1);
-  }
 
   /**
    * @return all suggestions in format [group1[sugg1, sugg2]]
    */
   @NotNull
   List<List<Suggestion>> getList() {
-    return Collections.unmodifiableList(myList);
+    return Collections.unmodifiableList(Arrays.asList(myPrefixGroup, myMainGroup));
   }
 
 
+  @Override
+  public String toString() {
+    return "SuggestionsBuilder{" +
+           "myPrefixGroup=" + myPrefixGroup +
+           ", myMainGroup=" + myMainGroup +
+           ", myCurrentGroup=" + myCurrentGroup +
+           '}';
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -109,20 +114,23 @@ public class SuggestionsBuilder {
 
     SuggestionsBuilder builder = (SuggestionsBuilder)o;
 
-    if (!myList.equals(builder.myList)) return false;
+    if (!myPrefixGroup.equals(builder.myPrefixGroup)) return false;
+    if (!myMainGroup.equals(builder.myMainGroup)) return false;
 
     return true;
   }
 
   @Override
   public int hashCode() {
-    return myList.hashCode();
+    int result = myPrefixGroup.hashCode();
+    result = 31 * result + myMainGroup.hashCode();
+    return result;
   }
 
-  @Override
-  public String toString() {
-    return "SuggestionsBuilder{" +
-           "myList=" + myList +
-           '}';
+  private static class MySuggestionComparator implements Comparator<Suggestion> {
+    @Override
+    public int compare(final Suggestion o1, final Suggestion o2) {
+      return o1.getText().compareTo(o2.getText());
+    }
   }
 }