1 /*******************************************************************************
2  * Copyright (c) 2005, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Bjorn Freeman-Benson - initial API and implementation
14  *     Wind River Systems - added support for IToggleBreakpointsTargetFactory
15  *******************************************************************************/
16 package org.eclipse.debug.examples.ui.pda.breakpoints;
17 
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.debug.core.DebugPlugin;
21 import org.eclipse.debug.core.model.IBreakpoint;
22 import org.eclipse.debug.core.model.ILineBreakpoint;
23 import org.eclipse.debug.examples.core.pda.DebugCorePlugin;
24 import org.eclipse.debug.examples.core.pda.breakpoints.PDALineBreakpoint;
25 import org.eclipse.debug.examples.core.pda.breakpoints.PDAWatchpoint;
26 import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
27 import org.eclipse.jface.text.BadLocationException;
28 import org.eclipse.jface.text.IDocument;
29 import org.eclipse.jface.text.IRegion;
30 import org.eclipse.jface.text.ITextSelection;
31 import org.eclipse.jface.viewers.ISelection;
32 import org.eclipse.ui.IWorkbenchPart;
33 import org.eclipse.ui.texteditor.IDocumentProvider;
34 import org.eclipse.ui.texteditor.ITextEditor;
35 
36 
37 /**
38  * Adapter to create breakpoints in PDA files.
39  */
40 public class PDABreakpointAdapter implements IToggleBreakpointsTargetExtension {
41 	@Override
toggleLineBreakpoints(IWorkbenchPart part, ISelection selection)42 	public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
43 		ITextEditor textEditor = getEditor(part);
44 		if (textEditor != null) {
45 			IResource resource = textEditor.getEditorInput().getAdapter(IResource.class);
46 			ITextSelection textSelection = (ITextSelection) selection;
47 			int lineNumber = textSelection.getStartLine();
48 			IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(DebugCorePlugin.ID_PDA_DEBUG_MODEL);
49 			for (int i = 0; i < breakpoints.length; i++) {
50 				IBreakpoint breakpoint = breakpoints[i];
51 				if (breakpoint instanceof ILineBreakpoint && resource.equals(breakpoint.getMarker().getResource())) {
52 					if (((ILineBreakpoint)breakpoint).getLineNumber() == (lineNumber + 1)) {
53 						// remove
54 						breakpoint.delete();
55 						return;
56 					}
57 				}
58 			}
59 			// create line breakpoint (doc line numbers start at 0)
60 			PDALineBreakpoint lineBreakpoint = new PDALineBreakpoint(resource, lineNumber + 1);
61 			DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(lineBreakpoint);
62 		}
63 	}
64 
65 	@Override
canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection)66 	public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
67 		return getEditor(part) != null;
68 	}
69 
70 	/**
71 	 * Returns the editor being used to edit a PDA file, associated with the
72 	 * given part, or <code>null</code> if none.
73 	 *
74 	 * @param part workbench part
75 	 * @return the editor being used to edit a PDA file, associated with the
76 	 * given part, or <code>null</code> if none
77 	 */
getEditor(IWorkbenchPart part)78 	private ITextEditor getEditor(IWorkbenchPart part) {
79 		if (part instanceof ITextEditor) {
80 			ITextEditor editorPart = (ITextEditor) part;
81 			IResource resource = editorPart.getEditorInput().getAdapter(IResource.class);
82 			if (resource != null) {
83 				String extension = resource.getFileExtension();
84 				if (extension != null && extension.equals("pda")) { //$NON-NLS-1$
85 					return editorPart;
86 				}
87 			}
88 		}
89 		return null;
90 	}
91 
92 	@Override
toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection)93 	public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
94 	}
95 
96 	@Override
canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection)97 	public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
98 		return false;
99 	}
100 
101 	@Override
toggleWatchpoints(IWorkbenchPart part, ISelection selection)102 	public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
103 		String[] variableAndFunctionName = getVariableAndFunctionName(part, selection);
104 		if (variableAndFunctionName != null && part instanceof ITextEditor && selection instanceof ITextSelection) {
105 			ITextEditor editorPart = (ITextEditor)part;
106 			int lineNumber = ((ITextSelection)selection).getStartLine();
107 			IResource resource = editorPart.getEditorInput().getAdapter(IResource.class);
108 			String var = variableAndFunctionName[0];
109 			String fcn = variableAndFunctionName[1];
110 			toggleWatchpoint(resource, lineNumber, fcn, var, true, true);
111 		}
112 	}
113 
114 	@Override
canToggleWatchpoints(IWorkbenchPart part, ISelection selection)115 	public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
116 		return getVariableAndFunctionName(part, selection) != null;
117 	}
118 
toggleWatchpoint(IResource resource, int lineNumber, String fcn, String var, boolean access, boolean modification)119 	protected void toggleWatchpoint(IResource resource, int lineNumber, String fcn, String var, boolean access,
120 		boolean modification) throws CoreException
121 	{
122 		// look for existing watchpoint to delete
123 		IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(DebugCorePlugin.ID_PDA_DEBUG_MODEL);
124 		for (int i = 0; i < breakpoints.length; i++) {
125 			IBreakpoint breakpoint = breakpoints[i];
126 			if (breakpoint instanceof PDAWatchpoint && resource.equals(breakpoint.getMarker().getResource())) {
127 				PDAWatchpoint watchpoint = (PDAWatchpoint)breakpoint;
128 				String otherVar = watchpoint.getVariableName();
129 				String otherFcn = watchpoint.getFunctionName();
130 				if (otherVar.equals(var) && otherFcn.equals(fcn)) {
131 					breakpoint.delete();
132 					return;
133 				}
134 			}
135 		}
136 		// create watchpoint
137 		PDAWatchpoint watchpoint = new PDAWatchpoint(resource, lineNumber + 1, fcn, var, access, modification);
138 		DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(watchpoint);
139 	}
140 
141 	/**
142 	 * Returns the variable and function names at the current line, or <code>null</code> if none.
143 	 *
144 	 * @param part text editor
145 	 * @param selection text selection
146 	 * @return the variable and function names at the current line, or <code>null</code> if none.
147 	 *  The array has two elements, the first is the variable name, the second is the function name.
148 	 */
getVariableAndFunctionName(IWorkbenchPart part, ISelection selection)149 	protected String[] getVariableAndFunctionName(IWorkbenchPart part, ISelection selection) {
150 		ITextEditor editor = getEditor(part);
151 		if (editor != null && selection instanceof ITextSelection) {
152 			ITextSelection textSelection = (ITextSelection) selection;
153 			IDocumentProvider documentProvider = editor.getDocumentProvider();
154 			try {
155 				documentProvider.connect(this);
156 				IDocument document = documentProvider.getDocument(editor.getEditorInput());
157 				IRegion region = document.getLineInformationOfOffset(textSelection.getOffset());
158 				String string = document.get(region.getOffset(), region.getLength()).trim();
159 				if (string.startsWith("var ")) { //$NON-NLS-1$
160 					String varName = string.substring(4).trim();
161 					String fcnName = getFunctionName(document, varName, document.getLineOfOffset(textSelection.getOffset()));
162 					return new String[] {varName, fcnName};
163 				}
164 			} catch (CoreException e) {
165 			} catch (BadLocationException e) {
166 			} finally {
167 				documentProvider.disconnect(this);
168 			}
169 		}
170 		return null;
171 	}
172 
173 	/**
174 	 * Returns the name of the function containing the given variable defined at the given
175 	 * line number in the specified document.
176 	 *
177 	 * @param document PDA source file
178 	 * @param varName variable name
179 	 * @param line line numbner at which the variable is defined
180 	 * @return name of function defining the variable
181 	 */
getFunctionName(IDocument document, String varName, int line)182 	private String getFunctionName(IDocument document, String varName, int line) {
183 		// This is a simple guess at the function name - look for the labels preceeding
184 		// the variable definition, and then see if there are any 'calls' to that
185 		// label. If none, assumet the variable is in the "_main_" function
186 		String source = document.get();
187 		int lineIndex = line - 1;
188 		while (lineIndex >= 0) {
189 			try {
190 				IRegion information = document.getLineInformation(lineIndex);
191 				String lineText = document.get(information.getOffset(), information.getLength());
192 				if (lineText.startsWith(":")) { //$NON-NLS-1$
193 					String label = lineText.substring(1);
194 					if (source.contains("call " + label)) { //$NON-NLS-1$
195 						return label;
196 					}
197 				}
198 				lineIndex--;
199 			} catch (BadLocationException e) {
200 			}
201 		}
202 		return "_main_"; //$NON-NLS-1$
203 	}
204 
205 	@Override
toggleBreakpoints(IWorkbenchPart part, ISelection selection)206 	public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
207 		if (canToggleWatchpoints(part, selection)) {
208 			toggleWatchpoints(part, selection);
209 		} else {
210 			toggleLineBreakpoints(part, selection);
211 		}
212 	}
213 
214 	@Override
canToggleBreakpoints(IWorkbenchPart part, ISelection selection)215 	public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
216 		return canToggleLineBreakpoints(part, selection) || canToggleWatchpoints(part, selection);
217 	}
218 }
219