jump to text attributes action

This commit is contained in:
Gregory.Shrago
2017-01-18 01:36:42 +03:00
parent e95a2677ee
commit fcb5e74a61
2 changed files with 198 additions and 0 deletions
@@ -0,0 +1,195 @@
/*
* 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.application.options.colors;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.ide.actions.ShowSettingsUtilImpl;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.editor.impl.DocumentMarkupModel;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.MarkupModel;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.colors.AttributesDescriptor;
import com.intellij.openapi.options.colors.ColorSettingsPage;
import com.intellij.openapi.options.colors.ColorSettingsPages;
import com.intellij.openapi.options.ex.Settings;
import com.intellij.openapi.options.newEditor.SettingsDialog;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.components.JBList;
import com.intellij.util.ObjectUtils;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.JBIterable;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.intellij.ui.SimpleTextAttributes.*;
/**
* @author gregsh
*/
public class JumpToTextAttributesAction extends DumbAwareAction {
public JumpToTextAttributesAction() {
setInjectedContext(true);
}
@Override
public void update(AnActionEvent e) {
Project project = e.getData(CommonDataKeys.PROJECT);
Editor editor = e.getData(CommonDataKeys.EDITOR);
e.getPresentation().setEnabledAndVisible(project != null && editor != null);
}
@Override
public void actionPerformed(AnActionEvent e) {
// todo handle ColorKey's as well
Project project = e.getData(CommonDataKeys.PROJECT);
Editor editor = e.getData(CommonDataKeys.EDITOR);
if (project == null || editor == null) return;
Map<TextAttributesKey, Pair<ColorSettingsPage, AttributesDescriptor>> keyMap = ContainerUtil.newHashMap();
Processor<RangeHighlighterEx> processor = r -> {
Object tt = r.getErrorStripeTooltip();
TextAttributesKey key = tt instanceof HighlightInfo ? ObjectUtils.chooseNotNull(
((HighlightInfo)tt).forcedTextAttributesKey, ((HighlightInfo)tt).type.getAttributesKey()) : null;
Pair<ColorSettingsPage, AttributesDescriptor> p = key == null ? null : ColorSettingsPages.getInstance().getAttributeDescriptor(key);
if (p != null) keyMap.put(key, p);
return true;
};
JBIterable<Editor> editors = editor instanceof EditorWindow ? JBIterable.of(editor, ((EditorWindow)editor).getDelegate()) : JBIterable.of(editor);
for (Editor ed : editors) {
TextRange selection = EditorUtil.getSelectionInAnyMode(ed);
MarkupModel forDocument = DocumentMarkupModel.forDocument(ed.getDocument(), project, false);
if (forDocument != null) {
((MarkupModelEx)forDocument).processRangeHighlightersOverlappingWith(selection.getStartOffset(), selection.getEndOffset(), processor);
}
((MarkupModelEx)ed.getMarkupModel()).processRangeHighlightersOverlappingWith(selection.getStartOffset(), selection.getEndOffset(), processor);
EditorHighlighter highlighter = ed instanceof EditorEx ? ((EditorEx)ed).getHighlighter() : null;
SyntaxHighlighter syntaxHighlighter = highlighter instanceof LexerEditorHighlighter ? ((LexerEditorHighlighter)highlighter).getSyntaxHighlighter() : null;
if (syntaxHighlighter != null) {
HighlighterIterator iterator = highlighter.createIterator(selection.getStartOffset());
while (!iterator.atEnd()) {
for (TextAttributesKey key : syntaxHighlighter.getTokenHighlights(iterator.getTokenType())) {
Pair<ColorSettingsPage, AttributesDescriptor> p = key == null ? null : ColorSettingsPages.getInstance().getAttributeDescriptor(key);
if (p != null) keyMap.put(key, p);
}
if (iterator.getEnd() >= selection.getEndOffset()) break;
iterator.advance();
}
}
}
if (keyMap.isEmpty()) {
HintManager.getInstance().showErrorHint(editor, "No text attributes found");
}
else if (keyMap.size() == 1) {
Pair<ColorSettingsPage, AttributesDescriptor> p = keyMap.values().iterator().next();
if (!openSettingsAndSelectKey(project, p.first, p.second)) {
HintManager.getInstance().showErrorHint(editor, "No appropriate settings page found");
}
}
else {
ArrayList<Pair<ColorSettingsPage, AttributesDescriptor>> attrs = ContainerUtil.newArrayList(keyMap.values());
Collections.sort(attrs, (o1, o2) -> StringUtil.naturalCompare(
o1.first.getDisplayName() + o1.second.getDisplayName(), o2.first.getDisplayName() + o2.second.getDisplayName()));
EditorColorsScheme colorsScheme = editor.getColorsScheme();
JBList<Pair<ColorSettingsPage, AttributesDescriptor>> list = new JBList<>(attrs);
list.setCellRenderer(new ColoredListCellRenderer<Pair<ColorSettingsPage, AttributesDescriptor>>() {
@Override
protected void customizeCellRenderer(@NotNull JList<? extends Pair<ColorSettingsPage, AttributesDescriptor>> list,
Pair<ColorSettingsPage, AttributesDescriptor> value,
int index,
boolean selected,
boolean hasFocus) {
TextAttributes ta = colorsScheme.getAttributes(value.second.getKey());
SimpleTextAttributes sa = fromTextAttributes(ta);
int style = STYLE_OPAQUE | sa.getStyle();
SimpleTextAttributes saOpaque = sa.derive(style, null, null, null);
SimpleTextAttributes saSelected = REGULAR_ATTRIBUTES.derive(sa.getStyle(), null, null, null);
List<String> split = StringUtil.split(value.first.getDisplayName() + "//" + value.second.getDisplayName(), "//");
for (int i = 0, len = split.size(); i < len; i++) {
boolean last = i == len - 1;
SimpleTextAttributes cur = !last ? REGULAR_ATTRIBUTES : selected ? saSelected : saOpaque;
if (last) append(" ", cur);
append(split.get(i), cur);
if (!last) append(" > ", GRAYED_ATTRIBUTES);
}
if (ta.getEffectType() == EffectType.BOXED && ta.getEffectColor() != null) {
append("\u25A2", REGULAR_ATTRIBUTES.derive(-1, ta.getEffectColor(), null, null));
}
if (ta.getErrorStripeColor() != null) {
append(" ", REGULAR_ATTRIBUTES.derive(STYLE_OPAQUE, null, ta.getErrorStripeColor(), null));
}
}
});
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle(StringUtil.notNullize(e.getPresentation().getText()))
.setMovable(false)
.setResizable(false)
.setRequestFocus(true)
.setItemChoosenCallback(() -> {
Pair<ColorSettingsPage, AttributesDescriptor> p = list.getSelectedValue();
if (p != null && !openSettingsAndSelectKey(project, p.first, p.second)) {
HintManager.getInstance().showErrorHint(editor, "No appropriate settings page found");
}
})
.createPopup().showInBestPositionFor(editor);
}
}
private static boolean openSettingsAndSelectKey(@NotNull Project project, @NotNull ColorSettingsPage page, @NotNull AttributesDescriptor descriptor) {
SettingsDialog dialog = (SettingsDialog)ShowSettingsUtilImpl.getDialog(
project, ShowSettingsUtilImpl.getConfigurableGroups(project, true), null);
Settings settings = Settings.KEY.getData(dialog);
ColorAndFontOptions configurable0 = settings == null ? null : settings.find(ColorAndFontOptions.class);
SearchableConfigurable configurable = configurable0 == null ? null : configurable0.findSubConfigurable(page.getDisplayName());
if (configurable == null) return false;
Runnable runnable = configurable.enableSearch(descriptor.getDisplayName());
ActionCallback callback = settings.select(configurable);
if (runnable != null) callback.doWhenDone(runnable);
dialog.show();
return true;
}
}
@@ -921,6 +921,9 @@
<add-to-group group-id="MaintenanceGroup" anchor="last"/>
</action>
<action id="JumpToTextAttributes" class="com.intellij.application.options.colors.JumpToTextAttributesAction"
text="Jump to Text Attributes" icon="AllIcons.General.EditColors"/>
<!-- Arrangement rules -->
<action id="Arrangement.Rule.Add"
use-shortcut-of="NewElement"