建立 NetBeans 模組,為 C/C++ 編輯器新增「標記實例高亮」功能:游標停留在變數/函式名稱上時,自動高亮同一文件中所有相同識別項出現處。
File → New Project → NetBeans Modules → Module,名稱 MarkOccurrences,代碼名稱基底 org.netbeans.modules.markoccurrences。File → New Project → Samples → C/C++ → Args,開啟 arg.c 供測試。package org.netbeans.modules.markoccurrences;
import java.awt.Color;
import java.lang.ref.WeakReference;
import javax.swing.JEditorPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.*;
import org.netbeans.api.editor.settings.AttributesUtilities;
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
import org.openide.cookies.EditorCookie;
import org.openide.loaders.DataObject;
public class MarkOccurrencesHighlighter implements CaretListener {
private static final AttributeSet DEFAULT_COLORS =
AttributesUtilities.createImmutable(StyleConstants.Background, new Color(236, 235, 163));
private final WeakReference<Document> weakDoc;
private final OffsetsBag bag;
private int lastCaret;
private RequestProcessor.Task task = null;
private static final int DELAY = 300; // ms
public MarkOccurrencesHighlighter(Document doc) {
this.weakDoc = new WeakReference<>(doc);
this.bag = new OffsetsBag(doc);
registerCaretListener(doc);
}
private void registerCaretListener(Document doc) {
DataObject dobj = NbEditorUtilities.getDataObject(doc);
JEditorPane[] panes = CsmUtilities.getOpenedPanesInEQ(dobj.getCookie(EditorCookie.class));
if (panes != null && panes.length > 0) panes[0].addCaretListener(this);
}
@Override
public void caretUpdate(CaretEvent e) {
lastCaret = e.getDot();
scheduleUpdate();
}
private void scheduleUpdate() {
if (task == null) {
task = RequestProcessor.getDefault().create(() -> {
CsmFile file = getCsmFile();
if (file != null) {
CsmReference ref = CsmReferenceResolver.getDefault().findReference(file, lastCaret);
if (ref != null && ref.getReferencedObject() != null) {
Collection<CsmReference> refs = CsmReferenceRepository.getDefault()
.getReferences(ref.getReferencedObject(), file, true);
for (CsmReference r : refs) {
bag.addHighlight(r.getStartOffset(), r.getEndOffset(), DEFAULT_COLORS);
}
}
}
}, true);
task.setPriority(Thread.MIN_PRIORITY);
}
task.cancel();
task.schedule(DELAY);
}
private CsmFile getCsmFile() {
Document doc = weakDoc.get();
if (doc == null) return null;
DataObject dobj = NbEditorUtilities.getDataObject(doc);
CsmFile file = CsmUtilities.getCsmFile(dobj, false);
return file;
}
public OffsetsBag getHighlightsBag() { return bag; }
}
package org.netbeans.modules.markoccurrences;
import javax.swing.text.Document;
import org.netbeans.spi.editor.highlighting.*;
import org.netbeans.spi.editor.highlighting.ZOrder;
public class MarkOccurrencesHighlightsLayerFactory implements HighlightsLayerFactory {
public static MarkOccurrencesHighlighter getMarkOccurrencesHighlighter(Document doc) {
MarkOccurrencesHighlighter h = (MarkOccurrencesHighlighter) doc.getProperty(MarkOccurrencesHighlighter.class);
if (h == null) doc.putProperty(MarkOccurrencesHighlighter.class, h = new MarkOccurrencesHighlighter(doc));
return h;
}
@Override
public HighlightsLayer[] createLayers(Context context) {
return new HighlightsLayer[] {
HighlightsLayer.create(
MarkOccurrencesHighlighter.class.getName(),
ZOrder.CARET_RACK.forPosition(2000),
true,
getMarkOccurrencesHighlighter(context.getDocument()).getHighlightsBag()
)
};
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN"
"https://www.netbeans.org/dtds/filesystem-1_1.dtd">
<filesystem>
<folder name="Editors">
<folder name="text">
<folder name="x-c++">
<file name="org-netbeans-modules-markoccurrences-MarkOccurrencesHighlightsLayerFactory.instance"/>
</folder>
<folder name="x-c">
<file name="org-netbeans-modules-markoccurrences-MarkOccurrencesHighlightsLayerFactory.instance"/>
</folder>
</folder>
</folder>
</filesystem>
Document/CsmFile 導致記憶體洩漏。arg.c,點擊變數名稱 (如 argc),同一文件所有 argc 即高亮顯示。