package net.sf.eclipsefp.haskell.debug.core.internal.debug; import java.util.regex.Matcher; import net.sf.eclipsefp.haskell.core.util.GHCiSyntax; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IRegisterGroup; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IVariable; import org.eclipse.jface.text.IDocument; import org.eclipse.ui.editors.text.TextFileDocumentProvider; import org.eclipse.ui.texteditor.IDocumentProvider; /** * stack frame for debugging haskell. For the moment there is always one stack frame. * @author JP Moresmau * */ public class HaskellStrackFrame extends HaskellDebugElement implements IStackFrame { private final HaskellThread thread; private int lineNumber=-1; private String name="HaskellStrackFrame"; //$NON-NLS-1$ /** * relative file name */ private String fileName; /** * full file name */ private String unprocessedFileName; private int charEnd=-1; private int charStart=-1; private boolean hasVariables=false; private final IProject project; public HaskellStrackFrame(final HaskellThread thread,final IProject p){ super(thread.getDebugTarget()); this.thread=thread; this.project=p; } @Override public int getCharEnd() { // return -1 return this.charEnd; } @Override public int getCharStart() { // return -1; return this.charStart; } @Override public int getLineNumber() { return lineNumber; } @Override public String getName() { return name; } public void setLocation( final String location ) { name=location; lineNumber=-1; fileName=null; unprocessedFileName=location; int endLineNumber = -1, tmpCharStart = -1, tmpCharEnd = -1; Matcher m=GHCiSyntax.BREAKPOINT_LOCATION_PATTERN.matcher( location ); if (m.matches()){ //name= m.group(1) ; endLineNumber=lineNumber=Integer.parseInt( m.group(2)) ; unprocessedFileName=m.group( 1 ); tmpCharStart=Integer.parseInt(m.group(3)); tmpCharEnd=Integer.parseInt(m.group(4)); } else { m=GHCiSyntax.BREAKPOINT_LOCATIONMULTILINE_PATTERN.matcher( location ); if (m.matches()){ lineNumber=Integer.parseInt( m.group(2)) ; endLineNumber=Integer.parseInt( m.group(4) ); unprocessedFileName=m.group( 1 ); tmpCharStart=Integer.parseInt(m.group(3)); tmpCharEnd=Integer.parseInt(m.group(5)); } else { m=GHCiSyntax.BREAKPOINT_LOCATION_NOEND_PATTERN.matcher( location ); if (m.matches()){ //name= m.group(1) ; endLineNumber=lineNumber=Integer.parseInt( m.group(2)) ; unprocessedFileName=m.group( 1 ); tmpCharStart=Integer.parseInt(m.group(3)); tmpCharEnd=tmpCharStart; } else { // It means there was an error endLineNumber = -1; } } } // Compute real character positions if (endLineNumber == -1) { // If there was an error lineNumber = -1; charStart = -1; charEnd = -1; } else { try { name=removeFilePrefix( location); hasVariables=true; // Get file name String fname=unprocessedFileName; IProject p = getProject(); String projectLocation=p.getLocation().toOSString(); if (fname.startsWith( projectLocation )){ fname=fname.substring( projectLocation.length()+1 ); } IFile f= p.getFile( fname ); IDocumentProvider prov=new TextFileDocumentProvider(); prov.connect( f ); try { IDocument doc=prov.getDocument( f ); //InputStream st = p.getFile( fname ).getContents(); // Get document info //IDocument d = new Document( ResourceUtil.readStream( st ) ); //st.close(); int initLineOffset = doc.getLineOffset( lineNumber - 1 ); int endLineOffset = doc.getLineOffset( endLineNumber - 1 ); charStart = initLineOffset + tmpCharStart - 1; charEnd = endLineOffset + tmpCharEnd; } finally { prov.disconnect( f ); } } catch (Exception e) { lineNumber = -1; charStart = -1; charEnd = -1; } } DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( this, DebugEvent.CHANGE, DebugEvent.CONTENT )}); } private String removeFilePrefix(final String fullLocation) { String ret=fullLocation; if (fullLocation!=null && fullLocation.length()>0){ IProject p=getProject(); String projectLocation=p.getLocation().toOSString(); int ix=fullLocation.indexOf( projectLocation ); if(ix>-1){ ret=fullLocation.substring( 0,ix )+fullLocation.substring( ix+projectLocation.length()-p.getName().length() ); } } return ret; } public void setHistoryLocation( final String location ) { name=null; lineNumber=-1; fileName=null; unprocessedFileName=location; int endLineNumber = -1, tmpCharStart = -1, tmpCharEnd = -1, idx=-1; Matcher m=GHCiSyntax.HIST_LOCATION_PATTERN.matcher( location ); if (m.matches()){ //name= m.group(1) ; idx=Integer.parseInt( m.group(1)); endLineNumber=lineNumber=Integer.parseInt( m.group(4)) ; unprocessedFileName=m.group( 3 ); tmpCharStart=Integer.parseInt(m.group(5)); tmpCharEnd=Integer.parseInt(m.group(6)); } else { m=GHCiSyntax.HIST_LOCATIONMULTILINE_PATTERN.matcher( location ); if (m.matches()){ idx=Integer.parseInt( m.group(1)); //name= m.group(1) ; lineNumber=Integer.parseInt( m.group(4)) ; endLineNumber=Integer.parseInt( m.group(6) ); unprocessedFileName=m.group( 3 ); tmpCharStart=Integer.parseInt(m.group(5)); tmpCharEnd=Integer.parseInt(m.group(7)); } else { // It means there was an error endLineNumber = -1; } } // Compute real character positions if (endLineNumber == -1) { // If there was an error lineNumber = -1; charStart = -1; charEnd = -1; } else { try { hasVariables=idx==1; name=location; int ix=name.indexOf( ':' ); name=removeFilePrefix( name.substring( ix+1 ).trim()); // Get file name String fname=unprocessedFileName; IProject p = getProject(); String projectLocation=p.getLocation().toOSString(); if (fname.startsWith( projectLocation )){ fname=fname.substring( projectLocation.length()+1 ); } IFile f= p.getFile( fname ); IDocumentProvider prov=new TextFileDocumentProvider(); prov.connect( f ); try { IDocument doc=prov.getDocument( f ); //InputStream st = p.getFile( fname ).getContents(); // Get document info //IDocument d = new Document( ResourceUtil.readStream( st ) ); //st.close(); int initLineOffset = doc.getLineOffset( lineNumber - 1 ); int endLineOffset = doc.getLineOffset( endLineNumber - 1 ); charStart = initLineOffset + tmpCharStart - 1; charEnd = endLineOffset + tmpCharEnd; } finally { prov.disconnect( f ); } } catch (Exception e) { lineNumber = -1; charStart = -1; charEnd = -1; } } DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( thread, DebugEvent.CHANGE, DebugEvent.CONTENT )}); } /** * @return the hasVariables */ @Override public boolean hasVariables() { return hasVariables; } public String getFileName() throws CoreException{ if (fileName==null){ fileName=unprocessedFileName; IProject p = getProject(); String projectLocation=p.getLocation().toOSString(); // return file relative to project, since we may have the same file in different folders (Main.hs) if (fileName.startsWith( projectLocation )){ fileName=fileName.substring( projectLocation.length()+1 ); return fileName; } // see http://sourceforge.net/projects/eclipsefp/forums/forum/371922/topic/5091430, we don't want to reduce only to our project // not found in my project, look in all reference projects for (IProject p1:getProject().getReferencedProjects()){ // String projectLocation1=p1.getLocation().toOSString(); // return file relative to project, since we may have the same file in different folders (Main.hs) if (fileName.startsWith( projectLocation1 )){ fileName=fileName.substring( projectLocation1.length()+1 ); break; } } } return fileName; } public IProject getProject() { /*String projectName=getLaunch().getLaunchConfiguration().getAttribute( ILaunchAttributes.PROJECT_NAME ,(String)null); if (projectName!=null){ IProject p=ResourcesPlugin.getWorkspace().getRoot().getProject( projectName ); return p; }*/ return project; } @Override public IRegisterGroup[] getRegisterGroups() { return new IRegisterGroup[0]; } @Override public IThread getThread() { return thread; } @Override public IVariable[] getVariables() throws DebugException { return getDebugTarget().getVariables(this); } @Override public boolean hasRegisterGroups() { return false; } @Override public boolean canStepInto() { return thread.canStepInto(); } @Override public boolean canStepOver() { return thread.canStepOver(); } @Override public boolean canStepReturn() { return thread.canStepReturn(); } @Override public boolean isStepping() { return thread.isStepping(); } @Override public void stepInto() throws DebugException { thread.stepInto(); } @Override public void stepOver() { thread.stepOver(); } @Override public void stepReturn() { thread.stepReturn(); } @Override public boolean canResume() { return thread.canResume(); } @Override public boolean canSuspend() { return thread.canSuspend(); } @Override public boolean isSuspended() { return thread.isSuspended(); } @Override public void resume() throws DebugException { thread.resume(); } @Override public void suspend() { thread.suspend(); } @Override public boolean canTerminate() { return thread.canTerminate(); } @Override public boolean isTerminated() { return thread.isTerminated(); } @Override public void terminate() throws DebugException { thread.terminate(); } public void setName( final String name ) { this.name = name; } public void setUnprocessedFileName( final String unprocessedFileName ) { this.unprocessedFileName = unprocessedFileName; this.name=removeFilePrefix( unprocessedFileName ); } }