@Override
	public void actionPerformed(ActionContext context) {
		GraphDisplayBroker graphDisplayBroker =
			plugin.getTool().getService(GraphDisplayBroker.class);
		if (graphDisplayBroker == null) {
			Msg.showError(this, plugin.getTool().getToolFrame(), "BSimFeatureVisualizer Error",
				"No graph display providers found: Please add a graph display provider to " +
					"your tool");
			return;
		}
		GhidraTable bsimFeatureTable = provider.getTable();
		BsfvTableModel model = provider.getModel();
		if (bsimFeatureTable.getSelectedRow() == -1) {
			return;
		}
		PcodeOpAST pcode = model.getOpAt(bsimFeatureTable.getSelectedRow());
		PcodeOpAST previousPcode = model.getPreviousOpAt(bsimFeatureTable.getSelectedRow());
		featureGraph = new AttributedGraph("BSim Feature Graph", featureGraphType);
		StringBuilder graphName = new StringBuilder();
		switch (model.getFeatureTypeAt(bsimFeatureTable.getSelectedRow())) {
			case DATA_FLOW:
				addDataFlowFeatureGraph(pcode, BSimFeatureGraphType.DATAFLOW_WINDOW_SIZE,
					featureGraph, true);
				graphName.append("DATA(");
				graphName.append(pcode.getMnemonic());
				graphName.append(")@");
				graphName.append(pcode.getSeqnum().getTarget());
				break;
			case CONTROL_FLOW:
				int blockIndex = model.getBlockIndexAt(bsimFeatureTable.getSelectedRow());
				addControlFlowFeatureGraph(blockIndex, featureGraph);
				graphName.append("CONTROL@");
				graphName.append(model.getBasicBlockStart(bsimFeatureTable.getSelectedRow()));
				break;
			case COMBINED:
				blockIndex = model.getBlockIndexAt(bsimFeatureTable.getSelectedRow());
				addControlFlowFeatureGraph(blockIndex, featureGraph);
				addDataFlowFeatureGraph(pcode, 1 + BSimFeatureGraphType.DATAFLOW_WINDOW_SIZE / 2,
					featureGraph, true);
				graphName.append("COMBINED(");
				graphName.append(pcode.getMnemonic());
				graphName.append(")@");
				graphName.append(pcode.getSeqnum().getTarget());
				break;
			case DUAL_FLOW:
				addDataFlowFeatureGraph(pcode, 1 + BSimFeatureGraphType.DATAFLOW_WINDOW_SIZE / 2,
					featureGraph, true);
				addDataFlowFeatureGraph(previousPcode,
					1 + BSimFeatureGraphType.DATAFLOW_WINDOW_SIZE / 2, featureGraph, false);
				graphName.append("DUAL(");
				graphName.append(pcode.getMnemonic());
				graphName.append(",");
				graphName.append(previousPcode.getMnemonic());
				graphName.append(")@");
				graphName.append(pcode.getSeqnum().getTarget());
				break;
			case COPY_SIG:
				blockIndex = model.getBlockIndexAt(bsimFeatureTable.getSelectedRow());
				addCopySigFeatureGraph(blockIndex, featureGraph);
				graphName.append("COPY_SIG@");
				graphName.append(model.getBasicBlockStart(bsimFeatureTable.getSelectedRow()));
				break;
			default:
				throw new IllegalArgumentException();
		}
		GraphDisplay graphDisplay = null;

		try {
			boolean reuseGraph = plugin.getReuseGraph();
			graphDisplay = graphDisplayBroker.getDefaultGraphDisplay(reuseGraph, TaskMonitor.DUMMY);
		}
		catch (GraphException e) {
			Msg.showError(this, null, "Graph Error", e.getMessage(), e);
			return;
		}

		if (graphDisplay == null) {
			Msg.showError(this, null, "null GraphDisplay", "null GraphDisplay");
		}
		else {
			try {
				//just use a dummy TaskMonitor since these graphs are small
				graphDisplay.setGraph(featureGraph, featureGraphOptions, graphName.toString(),
					false, TaskMonitor.DUMMY);
				graphDisplay.setGraphDisplayListener(new BsfvGraphDisplayListener(plugin.getTool(),
					plugin.getCurrentProgram(), graphDisplay));
			}
			catch (CancelledException e) {
				return;
			}
		}
		DecompilerHighlightService highlightService = plugin.getDecompilerHighlightService();
		if (highlightService == null) {
			Msg.showError(this, null, "DecompilerHighlightService not found",
				"DecompilerHighlightService not found");
		}
		else {
			if (!plugin.getHighlightByRow()) {
				BsfvTokenHighlightMatcher tokenMatcher = new BsfvTokenHighlightMatcher(
					model.getRowObject(bsimFeatureTable.getSelectedRow()), model.getHighFunction(),
					plugin);
				DecompilerHighlighter highlighter =
					highlightService.createHighlighter(BSIM_FEATURE_HIGHLIGHTER_NAME, tokenMatcher);
				highlighter.applyHighlights();
			}
		}

	}
Creates an action for drawing BSim feature graphs and highlighting relevant tokens in the 
decompiler.
@param provider provider
@param plugin plugin
Ghidra/Features/BSimFeatureVisualizer/src/main/java/ghidra/bsfv/HighlightAndGraphAction.java