package org.eclipse.dltk.tcl.internal.debug; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.debug.core.DebugException; import org.eclipse.dltk.compiler.CharOperation; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ISourceRange; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.dbgp.commands.IDbgpExtendedCommands; import org.eclipse.dltk.dbgp.exceptions.DbgpException; import org.eclipse.dltk.debug.core.IHotCodeReplaceProvider; import org.eclipse.dltk.debug.core.model.IScriptDebugTarget; import org.eclipse.dltk.debug.core.model.IScriptThread; public class TclHotCodeReplaceProvider implements IHotCodeReplaceProvider { public TclHotCodeReplaceProvider() { } @Override public void performCodeReplace(IScriptDebugTarget target, IResource[] resources) throws DebugException { final IScriptThread[] threads = (IScriptThread[]) target.getThreads(); if (threads.length > 0) { final IDbgpExtendedCommands extCmds = threads[0].getDbgpSession() .getExtendedCommands(); for (int i = 0; i < resources.length; ++i) { final String code = getResourceReplacementCode(resources[i]); if (code != null) { try { extCmds.evaluate(code); } catch (DbgpException e) { TclDebugPlugin.log(e); } } } } } private String getResourceReplacementCode(IResource resource) throws DebugException { final ISourceModule module = (ISourceModule) DLTKCore .create((IFile) resource); if (module == null) { return null; } final List<IMethod> procList = new ArrayList<>(); try { module.accept(element -> { if (element.getElementType() == IModelElement.METHOD) { procList.add((IMethod) element); return false; } return true; }); if (procList.isEmpty()) { return null; } final char[] input = org.eclipse.dltk.internal.core.util.Util .getResourceContentsAsCharArray((IFile) resource); final StringBuffer sb = new StringBuffer(); for (final IMethod method : procList) { final String[] types = collectNamespaces(method); if (types != null) { for (int j = 0; j < types.length; ++j) { sb.append("namespace eval " + types[j] + " {\n"); //$NON-NLS-1$ //$NON-NLS-2$ } sb.append("proc "); //$NON-NLS-1$ sb.append(method.getElementName()); final ISourceRange nameRange = method.getNameRange(); final int nameEnd = nameRange.getLength() + nameRange.getOffset(); final ISourceRange sourceRange = method.getSourceRange(); sb.append(input, nameEnd, sourceRange.getOffset() + sourceRange.getLength() - nameEnd); sb.append("\n"); //$NON-NLS-1$ for (int j = 0; j < types.length; ++j) { sb.append("}\n"); //$NON-NLS-1$ } } } if (sb.length() == 0) { return null; } return sb.toString(); } catch (ModelException e) { TclDebugPlugin.log(e); return null; } } /** * @param method * @return */ private String[] collectNamespaces(IMethod method) { final List<String> types = new ArrayList<>(); IModelElement parent = method.getParent(); while (parent.getElementType() == IModelElement.TYPE) { types.add(parent.getElementName()); parent = parent.getParent(); } if (parent.getElementType() != IModelElement.SOURCE_MODULE) { return null; } if (types.isEmpty()) { return CharOperation.NO_STRINGS; } Collections.reverse(types); return types.toArray(new String[types.size()]); } }