|
1 | 1 | /******************************************************************************* |
2 | | - * Copyright (c) 2000, 2016 IBM Corporation and others. |
| 2 | + * Copyright (c) 2000, 2026 IBM Corporation and others. |
3 | 3 | * |
4 | 4 | * This program and the accompanying materials |
5 | 5 | * are made available under the terms of the Eclipse Public License 2.0 |
|
17 | 17 | import java.lang.reflect.InvocationTargetException; |
18 | 18 | import java.util.ArrayList; |
19 | 19 | import java.util.List; |
| 20 | +import java.util.regex.Pattern; |
20 | 21 |
|
21 | 22 | import org.eclipse.swt.SWT; |
22 | 23 | import org.eclipse.swt.custom.StackLayout; |
| 24 | +import org.eclipse.swt.custom.StyleRange; |
23 | 25 | import org.eclipse.swt.custom.StyledText; |
| 26 | +import org.eclipse.swt.custom.StyledTextContent; |
24 | 27 | import org.eclipse.swt.events.SelectionEvent; |
25 | 28 | import org.eclipse.swt.events.SelectionListener; |
26 | 29 | import org.eclipse.swt.graphics.Color; |
|
54 | 57 | import org.eclipse.jface.util.PropertyChangeEvent; |
55 | 58 |
|
56 | 59 | import org.eclipse.jface.text.IWidgetTokenKeeper; |
| 60 | +import org.eclipse.jface.text.Region; |
57 | 61 | import org.eclipse.jface.text.source.IOverviewRuler; |
58 | 62 | import org.eclipse.jface.text.source.ISourceViewer; |
59 | 63 | import org.eclipse.jface.text.source.IVerticalRuler; |
@@ -585,6 +589,7 @@ private boolean isEqualInput(IEditorInput input1, IEditorInput input2) { |
585 | 589 | * @since 3.3 |
586 | 590 | */ |
587 | 591 | private StyledText fNoSourceTextWidget; |
| 592 | + private StyleRange currentSelection; |
588 | 593 | private volatile boolean disposed; |
589 | 594 |
|
590 | 595 | /** |
@@ -964,6 +969,80 @@ private static boolean hasSource(IClassFile file) { |
964 | 969 | } |
965 | 970 | } |
966 | 971 |
|
| 972 | + public void unhighlight() { |
| 973 | + if (disposed) { |
| 974 | + return; |
| 975 | + } |
| 976 | + if (currentSelection != null) { |
| 977 | + fNoSourceTextWidget.replaceStyleRanges(currentSelection.start, currentSelection.length, new StyleRange[0]); |
| 978 | + currentSelection= null; |
| 979 | + } |
| 980 | + } |
| 981 | + |
| 982 | + public void highlightInstruction(String methodName, String signature, long codeIndex, String colorPreferenceKey) { |
| 983 | + unhighlight(); |
| 984 | + StyledTextContent content= fNoSourceTextWidget.getContent(); |
| 985 | + |
| 986 | + int currentLine= findMethodStart(methodName, signature, content); |
| 987 | + Region instructionPosition= findInstruction(currentLine, content, codeIndex); |
| 988 | + if (instructionPosition == null) { |
| 989 | + return; |
| 990 | + } |
| 991 | + currentSelection= new StyleRange(instructionPosition.getOffset(), instructionPosition.getLength(), fNoSourceTextWidget.getForeground(), getColorPreference(colorPreferenceKey)); |
| 992 | + fNoSourceTextWidget.setStyleRange(currentSelection); |
| 993 | + |
| 994 | + // move cursor to ensure scrolling |
| 995 | + fNoSourceTextWidget.setSelection(instructionPosition.getOffset()); |
| 996 | + } |
| 997 | + |
| 998 | + private int findMethodStart(String methodName, String signature, StyledTextContent content) { |
| 999 | + int currentLine; |
| 1000 | + Pattern methodDescriptorPattern = Pattern.compile("\\s+// Method descriptor #\\d+ " + Pattern.quote(signature)); //$NON-NLS-1$ |
| 1001 | + for(currentLine = 0; currentLine < content.getLineCount() - 2; currentLine++) { |
| 1002 | + String line= content.getLine(currentLine); |
| 1003 | + if (methodDescriptorPattern.matcher(line).matches()) { |
| 1004 | + for(; currentLine < content.getLineCount(); currentLine++) { |
| 1005 | + // skip lines with leading slashes |
| 1006 | + line = content.getLine(currentLine); |
| 1007 | + if (!line.trim().startsWith("//")) { //$NON-NLS-1$ |
| 1008 | + break; |
| 1009 | + } |
| 1010 | + } |
| 1011 | + if (line.contains(" " + methodName + "(")) {//$NON-NLS-1$//$NON-NLS-2$ |
| 1012 | + break; |
| 1013 | + } |
| 1014 | + } |
| 1015 | + } |
| 1016 | + return currentLine; |
| 1017 | + } |
| 1018 | + |
| 1019 | + private Region findInstruction(int currentLine, StyledTextContent content, long codeIndex) { |
| 1020 | + for(currentLine++; currentLine < content.getLineCount(); currentLine++) { |
| 1021 | + String line= content.getLine(currentLine); |
| 1022 | + if (line.trim().startsWith("// Method descriptor")) { //$NON-NLS-1$ |
| 1023 | + // stop when reaching another method |
| 1024 | + return null; |
| 1025 | + } |
| 1026 | + if (line.trim().startsWith(String.valueOf(codeIndex))) { |
| 1027 | + return new Region(content.getOffsetAtLine(currentLine), line.length()); |
| 1028 | + } |
| 1029 | + } |
| 1030 | + return null; |
| 1031 | + } |
| 1032 | + |
| 1033 | + private Color getColorPreference(String key) { |
| 1034 | + String color= getPreferenceStore().getString(key); |
| 1035 | + String[] splitColor = color.split(","); //$NON-NLS-1$ |
| 1036 | + if (splitColor.length != 3) { |
| 1037 | + return new Color(0, 255, 0); |
| 1038 | + } |
| 1039 | + try { |
| 1040 | + return new Color(Integer.parseInt(splitColor[0]), Integer.parseInt(splitColor[1]), Integer.parseInt(splitColor[2])); |
| 1041 | + } catch (NumberFormatException e) { |
| 1042 | + return new Color(0, 255, 0); |
| 1043 | + } |
| 1044 | + } |
| 1045 | + |
967 | 1046 | /* |
968 | 1047 | * @see ClassFileDocumentProvider.InputChangeListener#inputChanged(IClassFileEditorInput) |
969 | 1048 | */ |
@@ -1032,4 +1111,11 @@ public void setFocus() { |
1032 | 1111 | fSourceAttachmentForm.setFocus(); |
1033 | 1112 | } |
1034 | 1113 | } |
| 1114 | + |
| 1115 | + /* |
| 1116 | + * Used for testing. |
| 1117 | + */ |
| 1118 | + public StyledText getNoSourceTextWidget() { |
| 1119 | + return fNoSourceTextWidget; |
| 1120 | + } |
1035 | 1121 | } |
0 commit comments