Bug 552392: [RCmd-Util] Enable 'show command line' and 'merge output'
for R CMD launch configurations

Change-Id: I61ee35c44d9ac22ad00d472f603e721c255f62b2
diff --git a/r/org.eclipse.statet.r.console.ui/plugin.xml b/r/org.eclipse.statet.r.console.ui/plugin.xml
index ec65b9e..f1a162f 100644
--- a/r/org.eclipse.statet.r.console.ui/plugin.xml
+++ b/r/org.eclipse.statet.r.console.ui/plugin.xml
@@ -26,7 +26,9 @@
             delegate="org.eclipse.statet.internal.r.cmd.ui.launching.RCmdLaunchDelegate"
             modes="run"
             name="%launchConfigurations_RCmd_name"
-            public="true">
+            public="true"
+            allowCommandLine="true"
+            allowOutputMerging="true">
       </launchConfigurationType>
    </extension>
    <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages">
diff --git a/r/org.eclipse.statet.r.console.ui/src/org/eclipse/statet/internal/r/cmd/ui/launching/RCmdLaunchDelegate.java b/r/org.eclipse.statet.r.console.ui/src/org/eclipse/statet/internal/r/cmd/ui/launching/RCmdLaunchDelegate.java
index 876ce6c..91d9e79 100644
--- a/r/org.eclipse.statet.r.console.ui/src/org/eclipse/statet/internal/r/cmd/ui/launching/RCmdLaunchDelegate.java
+++ b/r/org.eclipse.statet.r.console.ui/src/org/eclipse/statet/internal/r/cmd/ui/launching/RCmdLaunchDelegate.java
@@ -14,6 +14,8 @@
 
 package org.eclipse.statet.internal.r.cmd.ui.launching;
 
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -41,6 +43,9 @@
 import org.eclipse.ui.console.IConsole;
 import org.eclipse.ui.console.TextConsole;
 
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
 import org.eclipse.statet.ecommons.debug.core.util.LaunchUtils;
 import org.eclipse.statet.ecommons.debug.ui.config.LaunchConfigUtils;
 import org.eclipse.statet.ecommons.debug.ui.util.UnterminatedLaunchAlerter;
@@ -55,16 +60,58 @@
 import org.eclipse.statet.r.launching.ui.RErrorLineTracker;
 
 
+@NonNullByDefault
 public class RCmdLaunchDelegate extends LaunchConfigurationDelegate {
 	
 	
+	private static class RunData {
+		
+		private final IREnvConfiguration rEnvConfig;
+		
+		private final String cmd;
+		
+		private final List<String> command;
+		
+		private final IFileStore workingDirectory;
+
+		private final @Nullable IPath resourcePathAbsolute;
+		
+		public RunData(final IREnvConfiguration rEnvConfig, final String cmd, final List<String> command,
+				final IFileStore workingDirectory, final @Nullable IPath resourcePathAbsolute) {
+			this.rEnvConfig= rEnvConfig;
+			this.cmd= cmd;
+			this.command= command;
+			this.workingDirectory= workingDirectory;
+			this.resourcePathAbsolute= resourcePathAbsolute;
+		}
+		
+	}
+	
+	
 	public RCmdLaunchDelegate() {
 	}
 	
 	
 	@Override
-	public void launch(final ILaunchConfiguration configuration, final String mode,	final ILaunch launch,
-			final IProgressMonitor monitor) throws CoreException {
+	public String showCommandLine(final ILaunchConfiguration configuration, final String mode,
+			final @Nullable ILaunch launch,
+			final @Nullable IProgressMonitor monitor) throws CoreException {
+		final SubMonitor m= SubMonitor.convert(monitor, 5);
+		try {
+			final RunData data= getLaunchCommandData(configuration, m);
+			return (data != null) ?
+					LaunchUtils.generateCommandLine(data.command) :
+					""; //$NON-NLS-1$
+		}
+		finally {
+			m.done();
+		}
+	}
+	
+	@Override
+	public void launch(final ILaunchConfiguration configuration, final String mode,
+			final ILaunch launch,
+			final @Nullable IProgressMonitor monitor) throws CoreException {
 		final SubMonitor m= LaunchUtils.initProgressMonitor(configuration, monitor, 25);
 		final long timestamp= System.currentTimeMillis();
 		try {
@@ -72,71 +119,26 @@
 				return;
 			}
 			
-			final List<String> cmdLine = new ArrayList<>();
-			
-			// r env
-			final IREnvConfiguration renv = RLaunching.getREnvConfig(configuration, true);
-//			renv.validate();
-			
-			final String cmd = configuration.getAttribute(RCmdLaunching.R_CMD_COMMAND_ATTR_NAME, "").trim(); //$NON-NLS-1$
-			if (cmd.length() != 0) {
-				cmdLine.addAll(Arrays.asList(cmd.split(" "))); //$NON-NLS-1$
-			}
-			String arg1 = null;
-			if (cmdLine.size() > 0) {
-				arg1 = cmdLine.remove(0);
-			}
-			cmdLine.addAll(0, renv.getExecCommand(arg1, EnumSet.of(Exec.CMD, Exec.TERM)));
-			
-			m.worked(1);
-			if (m.isCanceled()) {
+			final RunData data= getLaunchCommandData(configuration, m);
+			if (data == null || m.isCanceled()) {
 				return;
 			}
 			
-			// working directory
-			final IFileStore workingDirectory = REnvTab.getWorkingDirectory(configuration);
-			
-			m.worked(1);
-			if (m.isCanceled()) {
-				return;
-			}
-			
-			// arguments
-			cmdLine.addAll(Arrays.asList(
-					LaunchUtils.getProcessArguments(configuration, RCmdLaunching.R_CMD_OPTIONS_ATTR_NAME) ));
-			
-			final String resourceValue = configuration.getAttribute(RCmdLaunching.R_CMD_RESOURCE_ATTR_NAME, ""); //$NON-NLS-1$
-			IFileStore resource = null;
-			IPath resourcePathAbsolute = null;
-			IPath resourcePathAuto = null;
-			if (resourceValue.length() > 0) {
-				resource = FileUtil.expandToLocalFileStore(resourceValue, workingDirectory, null);
-				final IPath workingDirectoryPath = URIUtil.toPath(workingDirectory.toURI());
-				resourcePathAuto = resourcePathAbsolute = URIUtil.toPath(resource.toURI());
-				if (workingDirectoryPath.isPrefixOf(resourcePathAuto)) {
-					resourcePathAuto = resourcePathAuto.setDevice(null);
-					resourcePathAuto = resourcePathAuto.removeFirstSegments(workingDirectoryPath.segmentCount());
-				}
-				cmdLine.add(resourcePathAuto.toString());
-			}
-			
-			m.worked(1);
-			if (m.isCanceled()) {
-				return;
-			}
-			
-			final ProcessBuilder builder = new ProcessBuilder(cmdLine);
-			builder.directory(workingDirectory.toLocalFile(EFS.NONE, null));
+			final ProcessBuilder builder= new ProcessBuilder(data.command);
+			builder.directory(data.workingDirectory.toLocalFile(EFS.NONE, null));
+			builder.redirectErrorStream(
+					configuration.getAttribute(DebugPlugin.ATTR_MERGE_OUTPUT, false) );
 			
 			// environment
-			final Map<String, String> envp = builder.environment();
-			LaunchUtils.configureEnvironment(envp, configuration, renv.getEnvironmentsVariables());
+			final Map<String, String> envp= builder.environment();
+			LaunchUtils.configureEnvironment(envp, configuration,
+					data.rEnvConfig.getEnvironmentsVariables() );
 			
 			// exec process
 			UnterminatedLaunchAlerter.registerLaunchType(RCmdLaunching.R_CMD_CONFIGURATION_TYPE_ID);
 			Process p;
 			try {
-				p = builder.start();
+				p= builder.start();
 			} catch (final IOException e) {
 				throw new CoreException(new Status(IStatus.ERROR, RConsoleUIPlugin.BUNDLE_ID, 0,
 						Messages.RCmd_LaunchDelegate_error_StartingExec, e ));
@@ -144,29 +146,29 @@
 			m.worked(10);
 			
 			// register process
-			final Map<String, String> processAttributes = new HashMap<>();
+			final Map<String, String> processAttributes= new HashMap<>();
 			processAttributes.put(IProcess.ATTR_PROCESS_TYPE, RCmdLaunching.R_CMD_PROCESS_TYPE);
-			final String processName = cmdLine.get(0) + ' ' + LaunchUtils.createProcessTimestamp(timestamp);
+			final String processName= data.command.get(0) + ' ' + LaunchUtils.createProcessTimestamp(timestamp);
 			final String label;
 			{
-				final StringBuilder sb = new StringBuilder(200);
+				final StringBuilder sb= new StringBuilder(200);
 				sb.append(LaunchUtils.createLaunchPrefix(configuration));
-				sb.append(' ').append(renv.getName());
-				sb.append(" : R ").append(cmd); //$NON-NLS-1$
-				if (resourcePathAbsolute != null) {
-					sb.append(' ').append(resourcePathAbsolute.toOSString());
+				sb.append(' ').append(data.rEnvConfig.getName());
+				sb.append(" : R ").append(data.cmd); //$NON-NLS-1$
+				if (data.resourcePathAbsolute != null) {
+					sb.append(' ').append(data.resourcePathAbsolute.toOSString());
 				}
 				sb.append(" ~ ").append(processName); //$NON-NLS-1$
-				label = sb.toString();
+				label= sb.toString();
 			}
 			
-			final IProcess process = DebugPlugin.newProcess(launch, p, processName, processAttributes);
+			final IProcess process= DebugPlugin.newProcess(launch, p, processName, processAttributes);
 			if (process == null) {
 				p.destroy();
 				throw new CoreException(new Status(IStatus.ERROR, RConsoleUIPlugin.BUNDLE_ID, 0,
 						Messages.RCmd_LaunchDelegate_error_ProcessHandle, null ));
 			}
-			process.setAttribute(IProcess.ATTR_CMDLINE, LaunchUtils.generateCommandLine(cmdLine));
+			process.setAttribute(IProcess.ATTR_CMDLINE, LaunchUtils.generateCommandLine(data.command));
 			process.setAttribute(IProcess.ATTR_PROCESS_LABEL, label);
 			
 			m.worked(5);
@@ -174,9 +176,9 @@
 				m.subTask(Messages.RCmd_LaunchDelegate_Running_label);
 			}
 			
-			final IConsole console = DebugUITools.getConsole(process);
+			final IConsole console= DebugUITools.getConsole(process);
 			if (console instanceof TextConsole) {
-				final RErrorLineTracker lineMatcher = new RErrorLineTracker(workingDirectory);
+				final RErrorLineTracker lineMatcher= new RErrorLineTracker(data.workingDirectory);
 				((TextConsole) console).addPatternMatchListener(lineMatcher);
 			}
 			
@@ -187,4 +189,59 @@
 		}
 	}
 	
+	private @Nullable RunData getLaunchCommandData(final ILaunchConfiguration configuration,
+			final SubMonitor m) throws CoreException {
+		final List<String> command= new ArrayList<>();
+		
+		// r env
+		final IREnvConfiguration rEnvConfig= RLaunching.getREnvConfig(configuration, true);
+//		renv.validate();
+		
+		final String cmd= configuration.getAttribute(RCmdLaunching.R_CMD_COMMAND_ATTR_NAME, "").trim(); //$NON-NLS-1$
+		if (!cmd.isEmpty()) {
+			command.addAll(Arrays.asList(cmd.split(" "))); //$NON-NLS-1$
+		}
+		String arg1= null;
+		if (command.size() > 0) {
+			arg1= command.remove(0);
+		}
+		command.addAll(0, rEnvConfig.getExecCommand(arg1, EnumSet.of(Exec.CMD, Exec.TERM)));
+		
+		m.worked(1);
+		if (m.isCanceled()) {
+			return null;
+		}
+		
+		// working directory
+		final IFileStore workingDirectory= REnvTab.getWorkingDirectory(configuration);
+		
+		m.worked(1);
+		if (m.isCanceled()) {
+			return null;
+		}
+		
+		// arguments
+		command.addAll(Arrays.asList(
+				LaunchUtils.getProcessArguments(configuration, RCmdLaunching.R_CMD_OPTIONS_ATTR_NAME) ));
+		
+		final String resourceValue= configuration.getAttribute(RCmdLaunching.R_CMD_RESOURCE_ATTR_NAME, ""); //$NON-NLS-1$
+		IFileStore resource= null;
+		IPath resourcePathAbsolute= null;
+		IPath resourcePathAuto= null;
+		if (resourceValue.length() > 0) {
+			resource= FileUtil.expandToLocalFileStore(resourceValue, workingDirectory, null);
+			final IPath workingDirectoryPath= nonNullAssert(URIUtil.toPath(workingDirectory.toURI()));
+			resourcePathAuto= resourcePathAbsolute= nonNullAssert(URIUtil.toPath(resource.toURI()));
+			if (workingDirectoryPath.isPrefixOf(resourcePathAuto)) {
+				resourcePathAuto= resourcePathAuto.setDevice(null);
+				resourcePathAuto= resourcePathAuto.removeFirstSegments(workingDirectoryPath.segmentCount());
+			}
+			command.add(resourcePathAuto.toString());
+		}
+		
+		m.worked(1);
+		
+		return new RunData(rEnvConfig, cmd, command, workingDirectory, resourcePathAbsolute);
+	}
+	
 }