Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Kolosovsky
2014-10-29 04:28:20 +03:00
8 changed files with 128 additions and 46 deletions
@@ -26,6 +26,7 @@ import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.psi.tree.ILightStubFileElementType;
import com.intellij.reference.SoftReference;
import com.intellij.util.CharTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,7 +51,7 @@ public class FileElement extends LazyParseableElement implements FileASTNode, Ge
return myCharTable;
}
private static final Key<LighterAST> ourTreeKey = Key.create("lighter.key");
private static final Key<SoftReference<LighterAST>> ourTreeKey = Key.create("lighter.key");
@Nullable
@Override
@@ -60,11 +61,11 @@ public class FileElement extends LazyParseableElement implements FileASTNode, Ge
LighterAST tree;
if (!isParsed()) {
tree = getUserData(ourTreeKey);
tree = SoftReference.dereference(getUserData(ourTreeKey));
if (tree == null) {
final ILightStubFileElementType<?> type = (ILightStubFileElementType)contentType;
tree = new FCTSBackedLighterAST(getCharTable(), type.parseContentsLight(this));
putUserData(ourTreeKey, tree);
putUserData(ourTreeKey, new SoftReference<LighterAST>(tree));
}
}
else {
@@ -22,9 +22,11 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.ContentManagerAdapter;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.switcher.QuickActionProvider;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.AwtVisitor;
import com.intellij.util.ui.UIUtil;
@@ -189,7 +191,21 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider
myToolWindow.getContentManager().addContentManagerListener(new ContentManagerAdapter() {
@Override
public void contentAdded(ContentManagerEvent event) {
setContentToolbarVisible(event.getContent(), getVisibilityValue());
JComponent component = event.getContent().getComponent();
setContentToolbarVisible(component, getVisibilityValue());
// support nested content managers, e.g. RunnerLayoutUi as content component
ContentManager contentManager =
component instanceof DataProvider ? PlatformDataKeys.CONTENT_MANAGER.getData((DataProvider)component) : null;
if (contentManager != null) contentManager.addContentManagerListener(this);
}
@Override
public void selectionChanged(ContentManagerEvent event) {
Content content = event.getContent();
if (content != null) {
setContentToolbarVisible(content.getComponent(), getVisibilityValue());
}
}
});
}
@@ -203,7 +219,7 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider
public void setSelected(AnActionEvent e, boolean state) {
myPropertiesComponent.setValue(getProperty(), String.valueOf(state), String.valueOf(true));
for (Content content : myToolWindow.getContentManager().getContents()) {
setContentToolbarVisible(content, state);
setContentToolbarVisible(content.getComponent(), state);
}
}
@@ -216,19 +232,17 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider
return myPropertiesComponent.getBoolean(getProperty(), true);
}
private static void setContentToolbarVisible(Content content, boolean state) {
LinkedList<JComponent> deque = ContainerUtil.newLinkedList(content.getComponent());
private static void setContentToolbarVisible(@NotNull JComponent root, boolean state) {
LinkedList<JComponent> deque = ContainerUtil.newLinkedList(root);
while(!deque.isEmpty()) {
JComponent component = deque.pollFirst();
if (!(component instanceof JPanel)) continue;
for (int i = 0, count = component.getComponentCount(); i < count; i++) {
Component c = component.getComponent(i);
if (c instanceof ActionToolbar) {
c.setVisible(state);
}
else if (c instanceof JPanel) {
deque.addLast((JPanel)c);
else if (c instanceof JPanel || c instanceof JLayeredPane || c instanceof JBTabs) {
deque.addLast((JComponent)c);
}
}
}
@@ -1,14 +1,20 @@
package com.jetbrains.python.edu;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.util.Couple;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.util.PairFunction;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.edu.actions.*;
import javax.swing.*;
import java.awt.*;
/**
@@ -27,12 +33,18 @@ public class StudyInstructionPainter extends EditorEmptyTextPainter {
UIUtil.TextPainter painter = new UIUtil.TextPainter().withLineSpacing(1.5f);
painter.appendLine("PyCharm Educational Edition").underlined(new JBColor(Gray._150, Gray._180));
painter.appendLine("Navigate to the next task window with Ctrl + Enter").smaller().withBullet();
painter.appendLine("Navigate between task windows with Ctrl + Shift + < and Ctrl + Shift + >").smaller().withBullet();
painter.appendLine("Navigate between tasks with Ctrl + < and Ctrl + >").smaller().withBullet();
painter.appendLine("Reset current task file with Ctrl + Shift + X").smaller().withBullet();
painter.appendLine("Check task with Alt + Ctrl + Enter").smaller().withBullet();
painter.appendLine("Get hint for the task window using Ctrl + 7").smaller().withBullet();
addAction(painter, "Navigate to the next task window", StudyNextWindowAction.ACTION_ID, StudyNextWindowAction.SHORTCUT2, true);
String shortcut1 = getShortcutText(StudyPrevWindowAction.ACTION_ID, StudyPrevWindowAction.SHORTCUT, false, false);
String shortcut2 = getShortcutText(StudyNextWindowAction.ACTION_ID, StudyNextWindowAction.SHORTCUT, false, false);
String text = "Navigate between task windows with " + shortcut1 +
" and " + shortcut2;
painter.appendLine(text).smaller().withBullet();
shortcut1 = getShortcutText(StudyPreviousStudyTaskAction.ACTION_ID, StudyPreviousStudyTaskAction.SHORTCUT, false, false);
shortcut2 = getShortcutText(StudyNextStudyTaskAction.ACTION_ID, StudyNextStudyTaskAction.SHORTCUT, false, false);
painter.appendLine("Navigate between tasks with " + shortcut1 + " and " + shortcut2).smaller().withBullet();
addAction(painter, "Reset current task file", StudyRefreshTaskFileAction.ACTION_ID, StudyRefreshTaskFileAction.SHORTCUT, false);
addAction(painter, "Check task", StudyCheckAction.ACTION_ID, StudyCheckAction.SHORTCUT, false);
addAction(painter, "Get hint for the task window", StudyShowHintAction.ACTION_ID, StudyShowHintAction.SHORTCUT, false);
painter.appendLine("To see your progress open the 'Course Description' panel").smaller().withBullet();
painter.draw(g, new PairFunction<Integer, Integer, Couple<Integer>>() {
@Override
@@ -42,4 +54,25 @@ public class StudyInstructionPainter extends EditorEmptyTextPainter {
}
});
}
private static void addAction(UIUtil.TextPainter painter, String text, String actionId, String defaultShortcutString, boolean useDefault) {
String shortcut = getShortcutText(actionId, defaultShortcutString, useDefault, true);
String actionText = text + " with " + shortcut;
painter.appendLine(actionText).smaller().withBullet();
}
private static String getShortcutText(String actionId, String defaultShortcutString, boolean useDefault, boolean wrapTag) {
AnAction action = ActionManager.getInstance().getAction(actionId);
String shortcut = "";
if (!useDefault) {
shortcut = KeymapUtil.getFirstKeyboardShortcutText(action);
}
if (shortcut.isEmpty() && defaultShortcutString != null) {
KeyboardShortcut keyboardShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(defaultShortcutString), null);
shortcut = KeymapUtil.getShortcutText(keyboardShortcut);
}
if (!wrapTag) {
return shortcut;
}
return "<shortcut>" + shortcut + "</shortcut>";
}
}
@@ -235,6 +235,10 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
private static void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString) {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
Shortcut[] shortcuts = keymap.getShortcuts(actionIdString);
if (shortcuts.length > 0) {
return;
}
Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
String[] actionsIds = keymap.getActionIds(studyActionShortcut);
for (String actionId : actionsIds) {
@@ -4,6 +4,8 @@ import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
import com.intellij.icons.AllIcons;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
@@ -16,6 +18,7 @@ import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
@@ -48,8 +51,9 @@ import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of StudyEditor which has panel with special buttons and task text
@@ -79,7 +83,14 @@ public class StudyEditor implements TextEditor {
return myTaskFile;
}
private static JButton addButton(@NotNull final JComponent parentComponent, String toolTipText, Icon icon) {
private static JButton addButton(@NotNull final JComponent parentComponent, String actionID, Icon icon,
@Nullable String defaultShortcutString) {
AnAction action = ActionManager.getInstance().getAction(actionID);
String toolTipText = KeymapUtil.createTooltipText(action.getTemplatePresentation().getText(), action);
if (!toolTipText.contains("(") && defaultShortcutString != null) {
KeyboardShortcut shortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(defaultShortcutString), null);
toolTipText += " (" + KeymapUtil.getShortcutText(shortcut) + ")";
}
JButton newButton = new JButton();
newButton.setToolTipText(toolTipText);
newButton.setIcon(icon);
@@ -192,13 +203,13 @@ public class StudyEditor implements TextEditor {
}
private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) {
myCheckButton = addButton(taskActionsPanel, "Check Task (Ctrl + Alt + Enter)", StudyIcons.Resolve);
myPrevTaskButton = addButton(taskActionsPanel, "Previous Task (Ctrl + &lt;)", StudyIcons.Prev);
myNextTaskButton = addButton(taskActionsPanel, "Next Task (Ctrl + >)", AllIcons.Actions.Forward);
myRefreshButton = addButton(taskActionsPanel, "Reset Task File (Ctrl + Shift + X)", AllIcons.Actions.Refresh);
JButton myShowHintButton = addButton(taskActionsPanel, "Show Hint for Task Window (Ctrl + 7)", StudyIcons.ShowHint);
myCheckButton = addButton(taskActionsPanel, StudyCheckAction.ACTION_ID, StudyIcons.Resolve, StudyCheckAction.SHORTCUT);
myPrevTaskButton = addButton(taskActionsPanel, StudyPreviousStudyTaskAction.ACTION_ID, StudyIcons.Prev, StudyPreviousStudyTaskAction.SHORTCUT);
myNextTaskButton = addButton(taskActionsPanel, StudyNextStudyTaskAction.ACTION_ID, AllIcons.Actions.Forward, StudyNextStudyTaskAction.SHORTCUT);
myRefreshButton = addButton(taskActionsPanel, StudyRefreshTaskFileAction.ACTION_ID, AllIcons.Actions.Refresh, StudyRefreshTaskFileAction.SHORTCUT);
JButton myShowHintButton = addButton(taskActionsPanel, StudyShowHintAction.ACTION_ID, StudyIcons.ShowHint, StudyShowHintAction.SHORTCUT);
if (!taskFile.getTask().getUserTests().isEmpty()) {
JButton runButton = addButton(taskActionsPanel, "Run", AllIcons.General.Run);
JButton runButton = addButton(taskActionsPanel, StudyRunAction.ACTION_ID, AllIcons.General.Run, null);
runButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -206,7 +217,7 @@ public class StudyEditor implements TextEditor {
studyRunAction.run(myProject);
}
});
JButton watchInputButton = addButton(taskActionsPanel, "Watch Test Input", StudyIcons.WatchInput);
JButton watchInputButton = addButton(taskActionsPanel, "WatchInputAction", StudyIcons.WatchInput, null);
watchInputButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -418,10 +418,7 @@ def run_python_code_linux(pid, python_code, connect_debugger_tracing=False, show
if not os.path.exists(target_dll):
raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
gdb_threads_settrace_file = os.path.join(filedir, 'linux', 'gdb_threads_settrace.py')
gdb_threads_settrace_file = os.path.normpath(gdb_threads_settrace_file)
if not os.path.exists(gdb_threads_settrace_file):
raise RuntimeError('Could not find file to settrace: %s' % gdb_threads_settrace_file)
gdb_threads_settrace_file = find_helper_script(filedir, 'gdb_threads_settrace.py')
# Note: we currently don't support debug builds
is_debug = 0
@@ -476,6 +473,15 @@ def run_python_code_linux(pid, python_code, connect_debugger_tracing=False, show
return out, err
def find_helper_script(filedir, script_name):
lldb_threads_settrace_file = os.path.join(filedir, 'linux', script_name)
lldb_threads_settrace_file = os.path.normpath(lldb_threads_settrace_file)
if not os.path.exists(lldb_threads_settrace_file):
raise RuntimeError('Could not find file to settrace: %s' % lldb_threads_settrace_file)
return lldb_threads_settrace_file
def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
assert '\'' not in python_code, 'Having a single quote messes with our command.'
filedir = os.path.dirname(__file__)
@@ -498,12 +504,10 @@ def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_d
if not os.path.exists(target_dll):
raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
lldb_threads_settrace_file = os.path.join(filedir, 'linux', 'lldb_threads_settrace.py')
lldb_threads_settrace_file = os.path.normpath(lldb_threads_settrace_file)
if not os.path.exists(lldb_threads_settrace_file):
raise RuntimeError('Could not find file to settrace: %s' % lldb_threads_settrace_file)
lldb_threads_settrace_file = find_helper_script(filedir, 'lldb_threads_settrace.py')
lldb_threads_prepare_file = find_helper_script(filedir, 'lldb_threads_prepare.py')
# Note: we currently don't support debug builds
is_debug = 0
# Note that the space in the beginning of each line in the multi-line is important!
cmd = [
@@ -521,8 +525,9 @@ def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_d
cmd.extend([
"-o 'process attach --pid %d'"%pid,
"-o 'command script import \'%s\''" % (lldb_threads_prepare_file,),
"-o 'expr (void*)dlopen(\"%s\", 2);'" % target_dll,
"-o 'expr (int)hello();'",
# "-o 'expr (int)hello();'",
"-o 'expr (int)DoAttach(%s, \"%s\", %s);'" % (
is_debug, python_code, show_debug_info),
])
@@ -531,7 +536,7 @@ def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_d
if connect_debugger_tracing:
cmd.extend([
# "-o 'expr (int) SetSysTraceFunc(0, 0);'",
"-o 'command script import %s'" % (lldb_threads_settrace_file,),
"-o 'command script import \'%s\''" % (lldb_threads_settrace_file,),
])
cmd.extend([
@@ -0,0 +1,18 @@
# This file is meant to be run inside lldb as a command before
# attaching the debugger to mark process threads as suspended
# to distinguish them from debugger threads later
def __lldb_init_module(debugger, internal_dict):
import lldb
try:
target = debugger.GetSelectedTarget()
if target:
process = target.GetProcess()
if process:
for thread in process:
# print('Marking process thread %d'%thread.GetThreadID())
internal_dict['_thread_%d' % thread.GetThreadID()] = True
# thread.Suspend()
except:
import traceback;traceback.print_exc()
@@ -2,11 +2,11 @@
# the attach_linux.dylib dll has already been loaded to settrace for all threads.
def __lldb_init_module(debugger, internal_dict):
# Command Initialization code goes here
print('Startup LLDB in Python!')
# print('Startup LLDB in Python!')
import lldb
try:
show_debug_info = 1
show_debug_info = 0
is_debug = 0
target = debugger.GetSelectedTarget()
if target:
@@ -14,15 +14,11 @@ def __lldb_init_module(debugger, internal_dict):
if process:
for thread in process:
# Get the first frame
print('Thread %s, suspended %s\n'%(thread, thread.IsStopped()))
# print('Thread %s, suspended %s\n'%(thread, thread.IsStopped()))
process.SetSelectedThread(thread)
if not thread.IsStopped():
error = process.Stop()
print(error)
if thread:
if internal_dict.get('_thread_%d' % thread.GetThreadID(), False):
frame = thread.GetSelectedFrame()
if frame:
print('Will settrace in: %s' % (frame,))
@@ -31,6 +27,6 @@ def __lldb_init_module(debugger, internal_dict):
error = res.GetError()
if error:
print(error)
thread.Resume()
thread.Resume()
except:
import traceback;traceback.print_exc()