Permalink
Browse files

allow evaluation of expressions in GHCi even if not suspended

  • Loading branch information...
1 parent 7579025 commit c78cd471fee92814b00ec51d4e52b41755ccbafb @JPMoresmau committed Oct 30, 2012
@@ -81,7 +81,7 @@ available at http://www.eclipse.org/legal/epl-v10.html.
id="net.sf.eclipsefp.haskell.core"
download-size="0"
install-size="0"
- version="2.3.2"
+ version="2.3.3"
unpack="false"/>
<plugin
@@ -116,7 +116,7 @@ available at http://www.eclipse.org/legal/epl-v10.html.
id="net.sf.eclipsefp.haskell.debug.ui"
download-size="0"
install-size="0"
- version="2.3.2"
+ version="2.3.3"
unpack="false"/>
<plugin
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-Name: %bundleName
Bundle-SymbolicName: net.sf.eclipsefp.haskell.core;singleton:=true
-Bundle-Version: 2.3.2
+Bundle-Version: 2.3.3
Bundle-Activator: net.sf.eclipsefp.haskell.core.HaskellCorePlugin
Bundle-Vendor: %bundleVendor
Bundle-Localization: plugin
@@ -11,7 +11,7 @@ Require-Bundle: org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)",
org.eclipse.ui;bundle-version="3.5.0",
org.eclipse.text;bundle-version="3.5.0",
net.sf.eclipsefp.haskell.util;bundle-version="2.3.2",
- net.sf.eclipsefp.haskell.hlint;bundle-version="2.3.1",
+ net.sf.eclipsefp.haskell.hlint;bundle-version="2.3.2",
org.eclipse.ui.editors;bundle-version="3.5.0",
org.eclipse.ui.ide;bundle-version="3.5.2",
net.sf.eclipsefp.haskell.buildwrapper;bundle-version="2.3.0"
@@ -46,6 +46,8 @@
public static final String TYPEOF="::"; //$NON-NLS-1$
public static final String UNIT="()"; //$NON-NLS-1$
+ public static final String IGNORING_BREAKPOINT="*** Ignoring breakpoint"+PlatformUtil.NL;//$NON-NLS-1$
+
public static String addModuleCommand(final String module){
return ":add *" +module; //$NON-NLS-1$
}
@@ -9,10 +9,14 @@
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import net.sf.eclipsefp.haskell.core.HaskellCorePlugin;
import net.sf.eclipsefp.haskell.core.preferences.ICorePreferenceNames;
@@ -24,6 +28,7 @@
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
@@ -80,7 +85,21 @@
private boolean disposed=false;
private boolean atEnd=false;
- private final HaskellThread thread=new HaskellThread( this );
+ private final HaskellThread thread;
+ /**
+ * the project on which we've laucnhed the debug session
+ */
+ private final IProject project;
+
+
+ /**
+ * keep a unique ID for the variables we create for :force
+ */
+ private final AtomicLong expCounter=new AtomicLong(System.currentTimeMillis());
+ /**
+ * keep all the :forced variables so that we don't show them in the variables view
+ */
+ private final Set<String> myVars=Collections.synchronizedSet( new HashSet<String>());
/**
* manages the number of instances
@@ -98,8 +117,25 @@ private static void instances(final int delta){
}
}
- public HaskellDebugTarget(final ILaunch launch, final IProcess process){
+ public HaskellDebugTarget(final ILaunch launch, final IProcess process,final List<String> files) throws CoreException{
setTarget( this );
+ // try {
+ String projectName=launch.getLaunchConfiguration().getAttribute( ILaunchAttributes.PROJECT_NAME ,(String)null);
+ if (projectName!=null){
+ project=ResourcesPlugin.getWorkspace().getRoot().getProject( projectName );
+ } else {
+ project=null;
+ }
+ thread=new HaskellThread( this, project);
+ if (files.size()>0){
+ String fn=files.get( 0 );
+
+ thread.getDefaultFrame().setUnprocessedFileName( fn );
+
+ }
+// } catch (CoreException ce){
+// HaskellDebugCore.log( ce.getLocalizedMessage(), ce );
+// }
this.fLaunch=launch;
this.fProcess=process;
this.fProcess.getStreamsProxy().getOutputStreamMonitor().addListener( this );
@@ -138,13 +174,13 @@ public boolean supportsBreakpoint( final IBreakpoint breakpoint ) {
IMarker marker = breakpoint.getMarker();
if (marker != null) {
try {
- String project = getLaunch().getLaunchConfiguration().getAttribute(ILaunchAttributes.PROJECT_NAME, (String)null);
- IProject launchProject=marker.getResource().getProject().getWorkspace().getRoot().getProject( project );
- if (launchProject!=null){
- if (launchProject.equals(marker.getResource().getProject())){
+ //String project = getLaunch().getLaunchConfiguration().getAttribute(ILaunchAttributes.PROJECT_NAME, (String)null);
+ //IProject launchProject=marker.getResource().getProject().getWorkspace().getRoot().getProject( project );
+ if (project!=null){
+ if (project.equals(marker.getResource().getProject())){
return true;
}
- for( IProject p: launchProject.getReferencedProjects() ) {
+ for( IProject p: project.getReferencedProjects() ) {
if (p.equals(marker.getResource().getProject())){
return true;
}
@@ -399,18 +435,28 @@ public void start() throws DebugException{
}
}
+
+ /**
+ * @return the atEnd
+ */
+ public boolean isAtEnd() {
+ return atEnd;
+ }
+
//boolean runContext=true;
@Override
- public synchronized void streamAppended( final String text, final IStreamMonitor monitor ) {
+ public void streamAppended( final String text, final IStreamMonitor monitor ) {
//boolean needContext=false;
synchronized( response ) {
+ //boolean oldAtEnd=atEnd;
atEnd=false;
response.append(text);
/**
* what do we do here? We got users complaining that sometimes we didn't realize GHCi was at the prompt
* the only explanation I could find is that the PROMPT_END string we look for got actually cut in two
* and so the text parameter never contained it. So if text is smaller than PROMPT_END, we check the whole response
*/
+
atEnd=text.length()>=GHCiSyntax.PROMPT_END.length()?text.endsWith( GHCiSyntax.PROMPT_END):response.toString().endsWith( GHCiSyntax.PROMPT_END);
if (atEnd){
if (thread.isSuspended()){
@@ -471,7 +517,11 @@ public void run() {
thread.setBreakpoint(null);
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( thread, DebugEvent.RESUME )});
response.setLength( 0 );
- }
+ } /*else if (!oldAtEnd){
+ response.setLength( 0 );
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( thread, DebugEvent.SUSPEND,DebugEvent.UNSPECIFIED )});
+ instances(1);
+ }*/
}
}
notify();
@@ -501,7 +551,7 @@ public synchronized void getHistory() {
l.clear();
String line=br.readLine();
while (line!=null){
- HaskellStrackFrame f2=new HaskellStrackFrame( thread );
+ HaskellStrackFrame f2=new HaskellStrackFrame( thread,project );
f2.setHistoryLocation( line );
if (f2.getName()!=null){
l.add( f2 );
@@ -534,7 +584,10 @@ public synchronized void getHistory() {
while (line!=null){
if (line.indexOf( GHCiSyntax.TYPEOF )>-1 && sb.length()>0){
- ret.add( new HaskellVariable( sb.toString(), frame ) );
+ HaskellVariable var=new HaskellVariable( sb.toString(), frame );
+ if (!myVars.contains( var.getName() )){
+ ret.add( var );
+ }
sb.setLength( 0 );
}
if (sb.length()>0){
@@ -544,7 +597,10 @@ public synchronized void getHistory() {
line=br.readLine();
}
if (sb.length()>0){
- ret.add( new HaskellVariable( sb.toString(), frame ) );
+ HaskellVariable var=new HaskellVariable( sb.toString(), frame );
+ if (!myVars.contains( var.getName() )){
+ ret.add( var );
+ }
}
return ret.toArray( new IVariable[ret.size()] );
} catch (IOException ioe){
@@ -555,7 +611,8 @@ public synchronized void getHistory() {
public void forceVariable(final HaskellVariable var)throws DebugException{
- sendRequest( GHCiSyntax.forceVariableCommand( var.getName() ), true );
+ //sendRequest( GHCiSyntax.forceVariableCommand( var.getName() ), true );
+ sendExpression( var.getName(), true );
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( var.getFrame(), DebugEvent.CHANGE,DebugEvent.CONTENT)});
/*String s=response.toString();
@@ -575,16 +632,47 @@ public void forceVariable(final HaskellVariable var)throws DebugException{
}
/**
+ * since :force only takes an identifier, we need to create an identifier for the expression, and force that
+ * @param expression
+ * @param force
+ * @return
+ * @throws DebugException
+ */
+ private String sendExpression(final String expression,final boolean force) throws DebugException{
+ if (force){
+ String fp="fp"+expCounter.getAndIncrement(); //$NON-NLS-1$
+ myVars.add( fp );
+ String exp=force?"let "+fp+"="+expression:expression; //$NON-NLS-1$ //$NON-NLS-2$
+ //GHCiSyntax.forceVariableCommand(expression):expression;
+ sendRequest(exp,true);
+ String val1=getResultWithoutPrompt();
+ sendRequest( GHCiSyntax.forceVariableCommand(fp), true );
+ String val2=getResultWithoutPrompt();
+ if (val2.startsWith( GHCiSyntax.IGNORING_BREAKPOINT )){ /** :force may give this message **/
+ val2=val2.substring( GHCiSyntax.IGNORING_BREAKPOINT.length() );
+ }
+ if (val2.startsWith( fp +" = ") ){//$NON-NLS-1$
+ val2=val2.substring( fp.length()+3 );
+ } else { /** this is an error, then, so we give the result of the initial expression **/
+ val2=val1;
+ }
+ return val2;
+ }
+ sendRequest(expression,true);
+ return getResultWithoutPrompt();
+
+ }
+ /**
* evaluate an arbitrary expression
* @param expression the expression
* @return the value and its type
* @throws DebugException
*/
- public synchronized HaskellValue evaluate(final String expression)throws DebugException{
+ public synchronized HaskellValue evaluate(final String expression,final boolean force)throws DebugException{
// get rid of any previous "it" in case of evaluation error
sendRequest(GHCiSyntax.UNIT,true);
- sendRequest(expression,true);
- String val=getResultWithoutPrompt();
+ String val=sendExpression( expression, force );
+ //getResultWithoutPrompt();
sendRequest(GHCiSyntax.TYPE_LAST_RESULT_COMMAND,true);
String type=getResultWithoutPrompt();
int ix=type.indexOf( GHCiSyntax.TYPEOF );
@@ -2,10 +2,8 @@
import java.util.regex.Matcher;
import net.sf.eclipsefp.haskell.core.util.GHCiSyntax;
-import net.sf.eclipsefp.haskell.debug.core.internal.launch.ILaunchAttributes;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
@@ -40,9 +38,12 @@
private boolean hasVariables=false;
- public HaskellStrackFrame(final HaskellThread thread){
+ private final IProject project;
+
+ public HaskellStrackFrame(final HaskellThread thread,final IProject p){
super(thread.getDebugTarget());
this.thread=thread;
+ this.project=p;
}
@Override
@@ -139,7 +140,7 @@ public void setLocation( final String location ) {
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[]{new DebugEvent( this, DebugEvent.CHANGE, DebugEvent.CONTENT )});
}
- private String removeFilePrefix(final String fullLocation) throws CoreException{
+ private String removeFilePrefix(final String fullLocation) {
String ret=fullLocation;
if (fullLocation!=null && fullLocation.length()>0){
IProject p=getProject();
@@ -263,13 +264,13 @@ public String getFileName() throws CoreException{
return fileName;
}
- public IProject getProject() throws CoreException {
- String projectName=getLaunch().getLaunchConfiguration().getAttribute( ILaunchAttributes.PROJECT_NAME ,(String)null);
+ 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 null;
+ }*/
+ return project;
}
@Override
@@ -371,4 +372,15 @@ public void terminate() throws DebugException {
}
+
+ public void setName( final String name ) {
+ this.name = name;
+ }
+
+
+ public void setUnprocessedFileName( final String unprocessedFileName ) {
+ this.unprocessedFileName = unprocessedFileName;
+ this.name=removeFilePrefix( unprocessedFileName );
+ }
+
}
@@ -4,6 +4,7 @@
import java.util.List;
import net.sf.eclipsefp.haskell.core.util.GHCiSyntax;
import net.sf.eclipsefp.haskell.debug.core.internal.util.CoreTexts;
+import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
@@ -19,13 +20,22 @@
public class HaskellThread extends HaskellDebugElement implements IThread {
private HaskellBreakpoint breakpoint;
private String stopLocation;
- private final HaskellStrackFrame frame=new HaskellStrackFrame( this );
+ private final HaskellStrackFrame frame;
private String name=CoreTexts.thread_default_name;
private final List<HaskellStrackFrame> historyFrames=new ArrayList<HaskellStrackFrame>();
- public HaskellThread(final HaskellDebugTarget target){
+ public HaskellThread(final HaskellDebugTarget target,final IProject p){
super( target );
+ frame=new HaskellStrackFrame( this,p );
+ }
+
+
+ /**
+ * @return the frame
+ */
+ public HaskellStrackFrame getDefaultFrame() {
+ return frame;
}
@Override
@@ -4,6 +4,8 @@
package net.sf.eclipsefp.haskell.debug.core.internal.launch;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import net.sf.eclipsefp.haskell.debug.core.internal.HaskellDebugCore;
import net.sf.eclipsefp.haskell.debug.core.internal.debug.HaskellDebugTarget;
@@ -45,8 +47,11 @@ protected void postProcessCreation( final ILaunchConfiguration configuration,
process.setAttribute( HaskellDebugCore.PROCESS_COMMAND_HISTORY, Boolean.TRUE.toString() );
+ List<String> fileNames=configuration.getAttribute( ILaunchAttributes.FILES, new ArrayList<String>() );
+
if (mode.equals( ILaunchManager.DEBUG_MODE )){
- HaskellDebugTarget hdt=new HaskellDebugTarget( launch, process );
+ HaskellDebugTarget hdt=new HaskellDebugTarget( launch, process,fileNames );
+
launch.addDebugTarget(hdt);
hdt.start();
}
Oops, something went wrong.

0 comments on commit c78cd47

Please sign in to comment.