// Copyright (c) 2003-2008 by Leif Frenzel. All rights reserved. // This code is made available under the terms of the Eclipse Public License, // version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html package net.sf.eclipsefp.haskell.debug.ui.internal.launch; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sf.eclipsefp.haskell.core.util.ResourceUtil; import net.sf.eclipsefp.haskell.debug.core.internal.HaskellDebugCore; import net.sf.eclipsefp.haskell.debug.core.internal.launch.HaskellLaunchDelegate; import net.sf.eclipsefp.haskell.debug.core.internal.launch.IInteractiveLaunchOperationDelegate; import net.sf.eclipsefp.haskell.debug.core.internal.launch.ILaunchAttributes; import net.sf.eclipsefp.haskell.debug.ui.internal.util.UITexts; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.osgi.util.NLS; /** <p>encapsulates the work involved in finding a launch configuration * (if one exists) for the selection and launching it.</p> * * @author Leif Frenzel */ public class InteractiveLaunchOperation extends LaunchOperation { static final String INTERACTIVE_CONFIG_TYPE = HaskellLaunchDelegate.class.getName(); private static final String FIRST_SELECTED_RESOURCE = "FIRST_SELECTED_RESOURCE"; //$NON-NLS-1$ // TODO we need an infrastructural change here: must have the executable // launching and the generic launching for interactive sessions in some // debug/debug.ui plugins, and let interactive environment interfacing // only declare the specific stuff private final IInteractiveLaunchOperationDelegate delegate; public InteractiveLaunchOperation( final IInteractiveLaunchOperationDelegate del ) { this.delegate = del; } @Override protected String getConfigTypeName() { return INTERACTIVE_CONFIG_TYPE; } // methods called from outside ////////////////////////////// public void launch( final IResource[] resources,final String mode, final IProgressMonitor monitor ) throws CoreException { IFile[] filesToLoad = SelectionAnalyzer.getSourcesToLoad( resources ); if( resources.length > 0 && resources[ 0 ] != null ) { IProject project = resources[ 0 ].getProject(); if(ResourceUtil.hasHaskellNature (project) ) { ILaunchConfiguration config = getConfiguration( resources, filesToLoad ); if( config != null ) { config.launch( mode, monitor ); } } } } // helping methods ////////////////// public ILaunchConfiguration getConfiguration( final IResource[] resources, final IFile[] files ) throws CoreException { List<ILaunchConfiguration> configurations = findConfig(delegate, resources,getConfigTypeName() ); ILaunchConfiguration result = null; int count = configurations.size(); if( count < 1 ) { // If there are no existing configs associated with the ICompilationUnit, // create one. result = createConfiguration( resources, files ); } else if( count == 1 ) { // If there is exactly one config associated with the ICompilationUnit, // return it. result = configurations.get( 0 ); } else { // Otherwise, if there is more than one config associated with the // ICompilationUnit, prompt the user to choose one. result = choose( configurations ); } return result; } protected String getConfigurationId(final IResource[] resources){ IContainer src=ResourceUtil.getSourceContainer( resources[0] ); IPath path=ResourceUtil.getSourceFolderRelativeName( resources[0] ); path=path.removeFileExtension(); return NLS.bind( UITexts.configuration_name, new Object[]{path.toPortableString() ,resources[0].getProject().getName(),src!=null?src.getProjectRelativePath().toPortableString():""}); //$NON-NLS-1$ } /** * set extra arguments that we know from preferences etc * subclasses can override * @param wc */ protected void setExtraArguments(final ILaunchConfigurationWorkingCopy wc){ // no extra arguments by default wc.setAttribute( ILaunchAttributes.EXTRA_ARGUMENTS, ILaunchAttributes.EMPTY ); } private ILaunchConfiguration createConfiguration( final IResource[] resources, final IFile[] files ) throws CoreException { ILaunchConfigurationType configType = getConfigType(); String s=getConfigurationId(resources); String id = createConfigId(s); IProject project = resources[ 0 ].getProject(); ILaunchConfigurationWorkingCopy wc = configType.newInstance( null, id ); //String exePath = delegate.getExecutable(); //wc.setAttribute( ILaunchAttributes.EXECUTABLE, exePath ); String projectLocation = project.getLocation().toOSString(); wc.setAttribute( ILaunchAttributes.WORKING_DIRECTORY, projectLocation ); //wc.setAttribute( ILaunchAttributes.ARGUMENTS, // getArguments(delegate, project, files ) ); setExtraArguments(wc); wc.setAttribute( ILaunchAttributes.DELEGATE, delegate.getClass().getName() ); List<String> fileNames=new ArrayList<>(files.length); for (IFile f:files){ fileNames.add(f.getProjectRelativePath().toPortableString()); } wc.setAttribute(ILaunchAttributes.FILES,fileNames); wc.setAttribute(ILaunchAttributes.SYNC_STREAMS,true); String projectName = ILaunchAttributes.PROJECT_NAME; wc.setAttribute( projectName, project.getName() ); wc.setAttribute( FIRST_SELECTED_RESOURCE, resources[ 0 ].getName() ); //wc.setAttribute( DebugPlugin.ATTR_PROCESS_FACTORY_ID,"net.sf.eclipsefp.haskell.debug.core.launch.REPLProcessFactory"); //wc.setAttribute( ILaunchAttributes.RELOAD_COMMAND, delegate.getReloadCommand() ); // by default, reload when saving, that's why interactive sessions are good wc.setAttribute( ILaunchAttributes.RELOAD,true); return wc.doSave(); } public static List<ILaunchConfiguration> findConfig( final IInteractiveLaunchOperationDelegate delegate, final IResource[] resources,final String configType ) throws CoreException { List<ILaunchConfiguration> result = Collections.emptyList(); ILaunchConfiguration[] configurations = LaunchOperation.getConfigurations(LaunchOperation.getConfigType( configType )); result = new ArrayList<>( configurations.length ); String cls=delegate.getClass().getName(); String exePath = delegate.getExecutable(); String projectName = resources[ 0 ].getProject().getName(); String firstResName = resources[ 0 ].getName(); for( int i = 0; i < configurations.length; i++ ) { ILaunchConfiguration configuration = configurations[ i ]; if( (getDelegate( configuration )==null || getDelegate( configuration ).equals( cls )) && HaskellDebugCore.getProjectName( configuration ).equals( projectName ) && getFirstResName( configuration ).equals( firstResName ) ) { String cExePath=getExePath( configuration ); // ensure exe path is current if (cExePath==null || !cExePath.equals( exePath )){ ILaunchConfigurationWorkingCopy wc=configuration.getWorkingCopy(); wc.setAttribute( ILaunchAttributes.EXECUTABLE, exePath); configuration=wc.doSave(); } result.add( configuration ); } } return result; } private static String getFirstResName( final ILaunchConfiguration config ) throws CoreException { String att = FIRST_SELECTED_RESOURCE; return config.getAttribute( att, ILaunchAttributes.EMPTY ); } public static String getDelegate(final ILaunchConfiguration config) throws CoreException{ return config.getAttribute( ILaunchAttributes.DELEGATE, (String)null ); } // public static String getArguments(final IInteractiveLaunchOperationDelegate delegate,final IProject project, final IFile[] files ) { // //IHaskellProject hsProject = HaskellProjectManager.get( project ); // return concatenate( delegate.createArguments( project, files ) ); // } public static String concatenate( final String[] args ) { StringBuffer sb = new StringBuffer(); if( args.length > 0 ) { sb.append( args[ 0 ] ); } for( int i = 1; i < args.length; i++ ) { sb.append( " " ); //$NON-NLS-1$ sb.append( args[ i ] ); } return sb.toString(); } }