mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Implementation of prefix based history model (PY-10985/IDEA-104596)
This commit is contained in:
committed by
Elizaveta Shashkova
parent
180f26b171
commit
4f63cb41a3
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.execution.console;
|
||||
|
||||
import com.intellij.openapi.util.ModificationTracker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ConsoleHistoryBaseModel extends ModificationTracker {
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
int getHistorySize();
|
||||
|
||||
void resetEntries(@NotNull List<String> entries);
|
||||
|
||||
void addToHistory(@Nullable String statement);
|
||||
|
||||
int getMaxHistorySize();
|
||||
|
||||
void removeFromHistory(String statement);
|
||||
|
||||
@NotNull
|
||||
List<String> getEntries();
|
||||
}
|
||||
+28
-27
@@ -17,6 +17,7 @@ package com.intellij.execution.console;
|
||||
|
||||
import com.intellij.AppTopics;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.execution.console.ConsoleHistoryModel.Entry;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.Disposable;
|
||||
@@ -54,9 +55,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.SafeFileOutputStream;
|
||||
import com.intellij.xml.util.XmlStringUtil;
|
||||
@@ -64,6 +63,7 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.xml.XppReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
@@ -80,9 +80,7 @@ public class ConsoleHistoryController {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("com.intellij.execution.console.ConsoleHistoryController");
|
||||
|
||||
/** @noinspection MismatchedQueryAndUpdateOfCollection*/
|
||||
private final static Map<String, ConsoleHistoryModel> ourModels = ConcurrentFactoryMap.createMap(key->
|
||||
new ConsoleHistoryModel(null), ContainerUtil::createConcurrentWeakValueMap);
|
||||
|
||||
private final static Map<LanguageConsoleView, ConsoleHistoryController> ourControllers =
|
||||
ContainerUtil.createConcurrentWeakMap(ContainerUtil.identityStrategy());
|
||||
|
||||
@@ -91,7 +89,7 @@ public class ConsoleHistoryController {
|
||||
private final AnAction myHistoryPrev = new MyAction(false, getKeystrokesUpDown(false));
|
||||
private final AnAction myBrowseHistory = new MyBrowseAction();
|
||||
private boolean myMultiline;
|
||||
private final ModelHelper myHelper;
|
||||
private ModelHelper myHelper;
|
||||
private long myLastSaveStamp;
|
||||
|
||||
@Deprecated
|
||||
@@ -100,15 +98,21 @@ public class ConsoleHistoryController {
|
||||
}
|
||||
|
||||
public ConsoleHistoryController(@NotNull ConsoleRootType rootType, @Nullable String persistenceId, @NotNull LanguageConsoleView console) {
|
||||
this(rootType, persistenceId, console, ourModels.get(getHistoryName(rootType, fixNullPersistenceId(persistenceId, console))));
|
||||
this(rootType, fixNullPersistenceId(persistenceId, console), console,
|
||||
ConsoleHistoryModelProvider.findModelForConsole(fixNullPersistenceId(persistenceId, console), console));
|
||||
}
|
||||
|
||||
private ConsoleHistoryController(@NotNull ConsoleRootType rootType, @Nullable String persistenceId,
|
||||
@NotNull LanguageConsoleView console, @NotNull ConsoleHistoryModel model) {
|
||||
myHelper = new ModelHelper(rootType, fixNullPersistenceId(persistenceId, console), model.copy());
|
||||
private ConsoleHistoryController(@NotNull ConsoleRootType rootType, @NotNull String persistenceId,
|
||||
@NotNull LanguageConsoleView console, @NotNull ConsoleHistoryModel model) {
|
||||
myHelper = new ModelHelper(rootType, persistenceId, model);
|
||||
myConsole = console;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setModel(@NotNull ConsoleHistoryModel model){
|
||||
myHelper = new ModelHelper(myHelper.myRootType, myHelper.myId, model);
|
||||
}
|
||||
|
||||
//@Nullable
|
||||
public static ConsoleHistoryController getController(@NotNull LanguageConsoleView console) {
|
||||
return ourControllers.get(console);
|
||||
@@ -214,7 +218,7 @@ public class ConsoleHistoryController {
|
||||
boolean result = myHelper.loadHistory(id, myConsole.getVirtualFile());
|
||||
String userValue = myHelper.getContent();
|
||||
if (prev != userValue && userValue != null) {
|
||||
setConsoleText(userValue, false, false);
|
||||
setConsoleText(new Entry(userValue, -1), false, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -238,8 +242,8 @@ public class ConsoleHistoryController {
|
||||
return myBrowseHistory;
|
||||
}
|
||||
|
||||
protected void setConsoleText(final String command, final boolean storeUserText, final boolean regularMode) {
|
||||
if (regularMode && myMultiline && StringUtil.isEmptyOrSpaces(command)) return;
|
||||
protected void setConsoleText(final Entry command, final boolean storeUserText, final boolean regularMode) {
|
||||
if (regularMode && myMultiline && StringUtil.isEmptyOrSpaces(command.getText())) return;
|
||||
final Editor editor = myConsole.getCurrentEditor();
|
||||
final Document document = editor.getDocument();
|
||||
new WriteCommandAction.Simple(myConsole.getProject()) {
|
||||
@@ -247,10 +251,11 @@ public class ConsoleHistoryController {
|
||||
public void run() {
|
||||
if (storeUserText) {
|
||||
String text = document.getText();
|
||||
if (Comparing.equal(command, text) && myHelper.getContent() != null) return;
|
||||
if (Comparing.equal(command.getText(), text) && myHelper.getContent() != null) return;
|
||||
myHelper.setContent(text);
|
||||
myHelper.getModel().setContent(text);
|
||||
}
|
||||
String text = StringUtil.notNullize(command);
|
||||
String text = StringUtil.notNullize(command.getText());
|
||||
int offset;
|
||||
if (regularMode) {
|
||||
if (myMultiline) {
|
||||
@@ -258,7 +263,7 @@ public class ConsoleHistoryController {
|
||||
}
|
||||
else {
|
||||
document.setText(text);
|
||||
offset = document.getTextLength();
|
||||
offset = command.getOffset() == -1 ? document.getTextLength() : command.getOffset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -302,15 +307,10 @@ public class ConsoleHistoryController {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
String command;
|
||||
if (myNext) {
|
||||
command = getModel().getHistoryNext();
|
||||
if (!myMultiline && command == null) return;
|
||||
}
|
||||
else {
|
||||
command = ObjectUtils.chooseNotNull(getModel().getHistoryPrev(), myMultiline ? "" : StringUtil.notNullize(myHelper.getContent()));
|
||||
}
|
||||
setConsoleText(command, myNext && !getModel().hasHistory(false), true);
|
||||
boolean hasHistory = getModel().hasHistory(); // need to check before next line's side effect
|
||||
Entry command = myNext ? getModel().getHistoryNext() : getModel().getHistoryPrev();
|
||||
if (!myMultiline && command == null) return;
|
||||
setConsoleText(command, myNext && !hasHistory, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -344,7 +344,7 @@ public class ConsoleHistoryController {
|
||||
else {
|
||||
final int lineCount = document.getLineCount();
|
||||
return (lineCount == 0 || document.getLineNumber(caretModel.getOffset()) == lineCount - 1) &&
|
||||
StringUtil.isEmptyOrSpaces(document.getText().substring(caretModel.getOffset()));
|
||||
(StringUtil.isEmptyOrSpaces(document.getText().substring(caretModel.getOffset())) || myHelper.getModel().prevOnLastLine());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,6 +376,7 @@ public class ConsoleHistoryController {
|
||||
return content;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<String> getContents() {
|
||||
List<String> entries = getModel().getEntries();
|
||||
@@ -412,7 +413,7 @@ public class ConsoleHistoryController {
|
||||
chooser.setSplitterOrientation(false);
|
||||
chooser.setSelectedIndex(Math.max(0, getModel().getHistorySize() - getModel().getCurrentIndex() - 1));
|
||||
if (chooser.showAndGet() && myConsole.getCurrentEditor().getComponent().isShowing()) {
|
||||
setConsoleText(chooser.getSelectedText(), false, true);
|
||||
setConsoleText(new Entry(chooser.getSelectedText(), -1), false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,40 +15,49 @@
|
||||
*/
|
||||
package com.intellij.execution.console;
|
||||
|
||||
import com.intellij.openapi.util.ModificationTracker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Yuli Fiterman
|
||||
*/
|
||||
public interface ConsoleHistoryModel extends ModificationTracker {
|
||||
void resetEntries(@NotNull List<String> entries);
|
||||
|
||||
void addToHistory(@Nullable String statement);
|
||||
|
||||
int getMaxHistorySize();
|
||||
|
||||
void removeFromHistory(String statement);
|
||||
|
||||
List<String> getEntries();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
int getHistorySize();
|
||||
public interface ConsoleHistoryModel extends ConsoleHistoryBaseModel {
|
||||
|
||||
@Nullable
|
||||
String getHistoryNext();
|
||||
Entry getHistoryNext();
|
||||
|
||||
@Nullable
|
||||
String getHistoryPrev();
|
||||
Entry getHistoryPrev();
|
||||
|
||||
boolean hasHistory(boolean next);
|
||||
|
||||
ConsoleHistoryModel copy();
|
||||
boolean hasHistory();
|
||||
|
||||
int getCurrentIndex();
|
||||
|
||||
void setContent(@NotNull String userContent);
|
||||
|
||||
/* if true then overrides the navigation behavior such that the down key on last line always navigates to prev instead of only when there
|
||||
are no more characters in from of the caret
|
||||
*/
|
||||
default boolean prevOnLastLine() {
|
||||
return false;
|
||||
}
|
||||
|
||||
class Entry {
|
||||
private final String text;
|
||||
private final int offset;
|
||||
|
||||
public Entry(String text, int offset) {
|
||||
this.text = text;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.execution.console;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface ConsoleHistoryModelProvider {
|
||||
ExtensionPointName<ConsoleHistoryModelProvider> EP_NAME = ExtensionPointName.create("com.intellij.consoleHistoryModelProvider");
|
||||
|
||||
@Nullable
|
||||
ConsoleHistoryModel createModel(@NotNull String persistenceId, @NotNull LanguageConsoleView consoleView);
|
||||
|
||||
static ConsoleHistoryModel findModelForConsole(@NotNull String persistenceId, @NotNull LanguageConsoleView consoleView) {
|
||||
for (ConsoleHistoryModelProvider provider : Extensions.getExtensions(EP_NAME)) {
|
||||
ConsoleHistoryModel model = provider.createModel(persistenceId, consoleView);
|
||||
if (model != null) {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
return DefaultConsoleHistoryModel.createModel(persistenceId);
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -18,23 +18,38 @@ package com.intellij.execution.console;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.util.SimpleModificationTracker;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Gregory.Shrago
|
||||
*/
|
||||
class DefaultConsoleHistoryModel extends SimpleModificationTracker implements ConsoleHistoryModel {
|
||||
public class DefaultConsoleHistoryModel extends SimpleModificationTracker implements ConsoleHistoryModel {
|
||||
/**
|
||||
* @noinspection FieldCanBeLocal
|
||||
*/
|
||||
|
||||
/**
|
||||
* @noinspection MismatchedQueryAndUpdateOfCollection
|
||||
*/
|
||||
private final static Map<String, DefaultConsoleHistoryModel> ourModels =
|
||||
ConcurrentFactoryMap.createMap(key -> new DefaultConsoleHistoryModel(null),
|
||||
ContainerUtil::createConcurrentWeakValueMap);
|
||||
|
||||
public static DefaultConsoleHistoryModel createModel(String persistenceId) {
|
||||
return ourModels.get(persistenceId).copy();
|
||||
}
|
||||
|
||||
private final Object myLock;
|
||||
private final LinkedList<String> myEntries;
|
||||
private int myIndex;
|
||||
private String myContent;
|
||||
|
||||
DefaultConsoleHistoryModel(@Nullable DefaultConsoleHistoryModel masterModel) {
|
||||
myEntries = masterModel == null ? new LinkedList<>() : masterModel.myEntries;
|
||||
@@ -96,6 +111,7 @@ class DefaultConsoleHistoryModel extends SimpleModificationTracker implements Co
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getEntries() {
|
||||
synchronized (myLock) {
|
||||
@@ -119,32 +135,33 @@ class DefaultConsoleHistoryModel extends SimpleModificationTracker implements Co
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getHistoryNext() {
|
||||
public Entry getHistoryNext() {
|
||||
synchronized (myLock) {
|
||||
if (myIndex >= 0) --myIndex;
|
||||
return getCurrentEntry();
|
||||
return new Entry(getCurrentEntry(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getHistoryPrev() {
|
||||
public Entry getHistoryPrev() {
|
||||
synchronized (myLock) {
|
||||
if (myIndex <= myEntries.size() - 1) ++myIndex;
|
||||
return getCurrentEntry();
|
||||
return new Entry(getCurrentEntry(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHistory(final boolean next) {
|
||||
public boolean hasHistory() {
|
||||
synchronized (myLock) {
|
||||
return next ? myIndex > 0 : myIndex < myEntries.size() - 1;
|
||||
return myIndex <= myEntries.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
String getCurrentEntry() {
|
||||
synchronized (myLock) {
|
||||
return myIndex >= 0 && myIndex < myEntries.size() ? myEntries.get(myIndex) : null;
|
||||
return myIndex >= 0 && myIndex < myEntries.size() ? myEntries.get(myIndex) :
|
||||
myIndex == myEntries.size() ? myContent : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,4 +170,9 @@ class DefaultConsoleHistoryModel extends SimpleModificationTracker implements Co
|
||||
return myIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContent(@NotNull String userContent) {
|
||||
myContent = userContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.execution.console
|
||||
|
||||
import com.intellij.execution.console.ConsoleHistoryModel.Entry
|
||||
import com.intellij.ide.ui.UISettings
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
import com.intellij.openapi.util.SimpleModificationTracker
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import gnu.trove.TIntStack
|
||||
|
||||
/**
|
||||
* @author Yuli Fiterman
|
||||
*/
|
||||
|
||||
private val MasterModels = ConcurrentFactoryMap.createMap<String, MasterModel>(
|
||||
{
|
||||
MasterModel()
|
||||
}, {
|
||||
ContainerUtil.createConcurrentWeakValueMap()
|
||||
})
|
||||
|
||||
|
||||
private fun assertDispatchThread() = ApplicationManager.getApplication().assertIsDispatchThread()
|
||||
|
||||
|
||||
fun createModel(persistenceId: String, console: LanguageConsoleView): ConsoleHistoryModel {
|
||||
val masterModel: MasterModel = MasterModels[persistenceId]!!
|
||||
fun getPrefixFromConsole(): String {
|
||||
val caretOffset = console.consoleEditor.caretModel.offset
|
||||
return console.editorDocument.getText(TextRange.create(0, caretOffset))
|
||||
}
|
||||
return PrefixHistoryModel(masterModel, ::getPrefixFromConsole)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class PrefixHistoryModel constructor(private val masterModel: MasterModel,
|
||||
private val getPrefixFn: () -> String) : ConsoleHistoryBaseModel by masterModel,
|
||||
ConsoleHistoryModel {
|
||||
|
||||
var userContent: String = ""
|
||||
override fun setContent(userContent: String) {
|
||||
this.userContent = userContent
|
||||
}
|
||||
|
||||
private var myEntries: List<String>? = null
|
||||
private var myCurrentIndex: Int = -1
|
||||
private var myPrevEntries: TIntStack = TIntStack()
|
||||
|
||||
init {
|
||||
resetIndex()
|
||||
}
|
||||
|
||||
override fun resetEntries(entries: MutableList<String>) {
|
||||
masterModel.resetEntries(entries)
|
||||
resetIndex()
|
||||
}
|
||||
|
||||
override fun addToHistory(statement: String?) {
|
||||
assertDispatchThread()
|
||||
if (statement.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
masterModel.addToHistory(statement)
|
||||
resetIndex()
|
||||
}
|
||||
|
||||
override fun removeFromHistory(statement: String?) {
|
||||
assertDispatchThread()
|
||||
if (statement.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
masterModel.removeFromHistory(statement)
|
||||
resetIndex()
|
||||
}
|
||||
|
||||
private fun resetIndex() {
|
||||
myEntries = null
|
||||
myCurrentIndex = -1
|
||||
myPrevEntries.clear();
|
||||
}
|
||||
|
||||
override fun getHistoryNext(): Entry? {
|
||||
val entries = myEntries ?: masterModel.entries
|
||||
val offset = if (myCurrentIndex == -1) entries.size else myCurrentIndex
|
||||
if (offset <= 0) {
|
||||
return null
|
||||
}
|
||||
val searchPrefix = getPrefixFn()
|
||||
val res = entries.withIndex().findLast { it.index < offset && it.value.startsWith(searchPrefix) } ?: return null
|
||||
|
||||
if (myEntries == null) {
|
||||
myEntries = entries
|
||||
}
|
||||
if (myCurrentIndex != -1) {
|
||||
myPrevEntries.push(myCurrentIndex)
|
||||
}
|
||||
|
||||
myCurrentIndex = res.index
|
||||
return Entry(res.value, searchPrefix.length)
|
||||
}
|
||||
|
||||
override fun getHistoryPrev(): Entry? {
|
||||
val entries = myEntries ?: return null
|
||||
if (myPrevEntries.size() > 0) {
|
||||
myCurrentIndex = myPrevEntries.pop()
|
||||
return entries[myCurrentIndex].let { Entry(it, -1) }
|
||||
}
|
||||
else {
|
||||
resetIndex()
|
||||
return Entry(userContent, -1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCurrentIndex(): Int =
|
||||
if (myCurrentIndex != -1) {
|
||||
myCurrentIndex
|
||||
}
|
||||
else {
|
||||
entries.size - 1
|
||||
}
|
||||
|
||||
override fun prevOnLastLine(): Boolean = true
|
||||
|
||||
override fun hasHistory(): Boolean = myEntries != null
|
||||
}
|
||||
|
||||
private class MasterModel(private val modTracker: SimpleModificationTracker = SimpleModificationTracker()) : ConsoleHistoryBaseModel, ModificationTracker by modTracker {
|
||||
|
||||
@Volatile private var myEntries: MutableList<String> = mutableListOf<String>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun getEntries(): MutableList<String> = myEntries.toMutableList()
|
||||
|
||||
override fun resetEntries(ent: List<String>) {
|
||||
myEntries = ent.toMutableList()
|
||||
}
|
||||
|
||||
override fun addToHistory(statement: String?) {
|
||||
if (statement == null) {
|
||||
return
|
||||
}
|
||||
val entries = myEntries
|
||||
entries.remove(statement)
|
||||
entries.add(statement)
|
||||
if (entries.size >= maxHistorySize) {
|
||||
entries.removeAt(0)
|
||||
}
|
||||
modTracker.incModificationCount()
|
||||
}
|
||||
|
||||
override fun removeFromHistory(statement: String?) {
|
||||
if (statement == null) {
|
||||
return
|
||||
}
|
||||
val entries = myEntries;
|
||||
entries.remove(statement)
|
||||
modTracker.incModificationCount()
|
||||
}
|
||||
|
||||
override fun getMaxHistorySize(): Int = UISettings.instance.consoleCommandHistoryLimit
|
||||
|
||||
override fun isEmpty(): Boolean = entries.isEmpty()
|
||||
|
||||
override fun getHistorySize(): Int = entries.size
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.execution.console;
|
||||
|
||||
|
||||
import com.intellij.openapi.fileTypes.PlainTextLanguage;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.testFramework.EditorTestUtil;
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
|
||||
import com.intellij.testFramework.TestActionEvent;
|
||||
|
||||
|
||||
/**
|
||||
* @author Yuli Fiterman
|
||||
*/
|
||||
public class ConsoleHistoryConstrollerTest extends LightPlatformCodeInsightTestCase {
|
||||
private LanguageConsoleImpl myConsole;
|
||||
private ConsoleHistoryController myHistoryController;
|
||||
private ConsoleExecuteAction myExecAction;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
myConsole = new LanguageConsoleImpl(getProject(), "Test console", PlainTextLanguage.INSTANCE);
|
||||
myConsole.setConsoleEditorEnabled(true);
|
||||
myExecAction = new ConsoleExecuteAction(myConsole, new MockExecutionActionHandler());
|
||||
myExecAction.registerCustomShortcutSet(myExecAction.getShortcutSet(), myConsole.getConsoleEditor().getComponent());
|
||||
myHistoryController = new ConsoleHistoryController(new ConsoleRootType("test console", null) {
|
||||
}, null, myConsole);
|
||||
myHistoryController.setModel(PrefixHistoryModelKt.createModel("default", myConsole));
|
||||
myHistoryController.install();
|
||||
myConsole.setConsoleEditorEnabled(true);
|
||||
myEditor = myConsole.getConsoleEditor();
|
||||
myVFile = myConsole.getVirtualFile();
|
||||
myFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(myEditor.getDocument());
|
||||
}
|
||||
|
||||
private void setCaretWithText(String markedText) {
|
||||
myConsole.setInputText(markedText);
|
||||
EditorTestUtil.CaretAndSelectionState state = EditorTestUtil.extractCaretAndSelectionMarkers(myConsole.getEditorDocument());
|
||||
EditorTestUtil.setCaretsAndSelection(myConsole.getConsoleEditor(), state);
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
}
|
||||
|
||||
private void executeCommand() {
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
myExecAction.actionPerformed(new TestActionEvent());
|
||||
}
|
||||
|
||||
private void execStatementList1() {
|
||||
myConsole.setInputText("Statement 1");
|
||||
executeCommand();
|
||||
myConsole.setInputText("Statement 2");
|
||||
executeCommand();
|
||||
|
||||
myConsole.setInputText("Statement 3");
|
||||
executeCommand();
|
||||
|
||||
myConsole.setInputText("Different Prefix");
|
||||
executeCommand();
|
||||
|
||||
assertEquals("", myConsole.getEditorDocument().getText());
|
||||
}
|
||||
|
||||
private void consoleNext() {
|
||||
myHistoryController.getHistoryNext().actionPerformed(null);
|
||||
}
|
||||
|
||||
private void consolePrev() {
|
||||
myHistoryController.getHistoryPrev().actionPerformed(null);
|
||||
}
|
||||
|
||||
public void testNavigateUp() {
|
||||
execStatementList1();
|
||||
setCaretWithText("Statement<caret> 4");
|
||||
consoleNext();
|
||||
checkResultByText("Statement<caret> 3");
|
||||
}
|
||||
|
||||
public void testNavigateDown() {
|
||||
execStatementList1();
|
||||
setCaretWithText("Statement<caret> 4");
|
||||
consoleNext();
|
||||
consolePrev();
|
||||
checkResultByText("Statement 4<caret>");
|
||||
}
|
||||
|
||||
public void testNavigateUpNoPrefix() {
|
||||
execStatementList1();
|
||||
setCaretWithText("<caret>Statement 4");
|
||||
consoleNext();
|
||||
checkResultByText("Different Prefix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
try {
|
||||
|
||||
Disposer.dispose(myConsole);
|
||||
myVFile = null;
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MockExecutionActionHandler extends BaseConsoleExecuteActionHandler {
|
||||
|
||||
public MockExecutionActionHandler() {
|
||||
super(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -912,6 +912,7 @@
|
||||
interface="org.jetbrains.uast.UastLanguagePlugin"/>
|
||||
|
||||
<extensionPoint name="breadcrumbsInfoProvider" interface="com.intellij.ui.breadcrumbs.BreadcrumbsProvider"/>
|
||||
<extensionPoint name="consoleHistoryModelProvider" interface="com.intellij.execution.console.ConsoleHistoryModelProvider"/>
|
||||
|
||||
<extensionPoint name="filetype.prebuiltStubsProvider"
|
||||
beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint">
|
||||
|
||||
@@ -628,6 +628,7 @@
|
||||
<projectService serviceInterface="com.jetbrains.python.debugger.containerview.PyDataView" serviceImplementation="com.jetbrains.python.debugger.containerview.PyDataView"/>
|
||||
|
||||
<createFromTemplateHandler implementation="com.jetbrains.python.packaging.setupPy.PyCreateSetupPyFromTemplateHandler"/>
|
||||
<consoleHistoryModelProvider implementation="com.jetbrains.python.console.PyConsoleHistoryModelProvider"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.console;
|
||||
|
||||
import com.intellij.execution.console.ConsoleHistoryModel;
|
||||
import com.intellij.execution.console.ConsoleHistoryModelProvider;
|
||||
import com.intellij.execution.console.LanguageConsoleView;
|
||||
import com.intellij.execution.console.PrefixHistoryModelKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Yuli Fiterman
|
||||
*/
|
||||
public class PyConsoleHistoryModelProvider implements ConsoleHistoryModelProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public ConsoleHistoryModel createModel(@NotNull String persistenceId, @NotNull LanguageConsoleView consoleView) {
|
||||
return consoleView instanceof PythonConsoleView ? PrefixHistoryModelKt.createModel(persistenceId, consoleView) : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user