/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package com.github.rustdt.tooling.ops;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import melnorme.lang.tooling.common.ops.IOperationMonitor;
import melnorme.lang.tooling.toolchain.ops.AbstractToolInvocationOperation;
import melnorme.lang.tooling.toolchain.ops.IToolOperationService;
import melnorme.lang.tooling.toolchain.ops.OperationSoftFailure;
import melnorme.lang.tooling.toolchain.ops.SourceOpContext;
import melnorme.lang.utils.validators.LocationOrSinglePathValidator;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.collections.Indexable;
import melnorme.utilbox.concurrency.OperationCancellation;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.fields.validation.ValidatedValueSource;
import melnorme.utilbox.misc.FileUtil;
import melnorme.utilbox.misc.Location;
import melnorme.utilbox.misc.StringUtil;
import melnorme.utilbox.status.Severity;
import melnorme.utilbox.status.StatusException;
public abstract class RacerOperation<RESULTDATA> extends AbstractToolInvocationOperation<RESULTDATA> {
protected final ValidatedValueSource<Path> racerPath;
protected final ValidatedValueSource<Location> sdkSrcLocation;
protected final SourceOpContext sourceOpContext;
protected final String source;
protected final boolean useSubstituteFile;
protected Location substituteFile;
public RacerOperation(IToolOperationService opHelper,
ValidatedValueSource<Path> racerPath, ValidatedValueSource<Location> sdkSrcLocation,
SourceOpContext sourceOpContext) {
super(opHelper, "NOT_USED");
this.racerPath = racerPath;
this.sdkSrcLocation = sdkSrcLocation;
this.sourceOpContext = assertNotNull(sourceOpContext);
this.source = sourceOpContext.getSource();
this.useSubstituteFile = sourceOpContext.isDocumentDirty();
}
@Override
protected String getToolName() throws CommonException {
return "Racer";
}
protected static ArrayList2<String> getArguments(String opName, int line_0, int col_0, Location fileLocation) {
ArrayList2<String> arguments = ArrayList2.create(opName);
arguments.add(Integer.toString(line_0 + 1)); // use one-based index
arguments.add(Integer.toString(col_0)); // But this one is zero-based index
arguments.add(fileLocation.toPathString());
return arguments;
}
@Override
public RESULTDATA executeToolOperation(IOperationMonitor om)
throws CommonException, OperationCancellation, OperationSoftFailure {
if(useSubstituteFile()) {
assertNotNull(source);
createSubstituteFile(source);
}
RESULTDATA result = super.executeToolOperation(om);
if(useSubstituteFile()) {
substituteFile.toFile().delete();
}
return result;
}
protected void createSubstituteFile(String source) throws CommonException {
try {
substituteFile = Location.create_fromValid(Files.createTempFile("RustDT-", "-racer_substitute_file.rs"));
FileUtil.writeStringToFile(substituteFile.toFile(), source, StringUtil.UTF8);
} catch(IOException e) {
throw new CommonException("Error creating substitute file for Racer: ", e);
}
}
protected boolean useSubstituteFile() {
return useSubstituteFile;
}
@Override
protected ProcessBuilder createProcessBuilder() throws CommonException {
String toolExePath = racerPath.getValidatedValue().toString();
String rustSrcPath = sdkSrcLocation.getValidatedValue().toString();
ArrayList2<String> cmdLine = ArrayList2.create(toolExePath);
cmdLine.addAll2(getRacerArguments());
if(substituteFile != null) {
cmdLine.add(substituteFile.toPathString());
}
ProcessBuilder pb = new ProcessBuilder(cmdLine);
pb.environment().put("RUST_SRC_PATH", rustSrcPath);
return pb;
}
protected abstract Indexable<String> getRacerArguments() throws CommonException;
public static class RustRacerLocationValidator extends LocationOrSinglePathValidator {
public RustRacerLocationValidator() {
super("Racer executable:");
fileOnly = true;
}
}
/* ----------------- ----------------- */
protected RacerCompletionOutputParser createRacerOutputParser(int offset) {
RacerCompletionOutputParser parser = new RacerCompletionOutputParser(offset) {
@Override
protected void handleUnknownLineFormat(CommonException ce) throws CommonException {
opHelper.logStatus(ce.toStatusException(Severity.WARNING));
}
@Override
protected void handleInvalidMatchKindString(String matchKindString) throws CommonException {
opHelper.logStatus(new StatusException(Severity.WARNING,
"Unknown Match Kind: " + matchKindString));
}
};
return parser;
}
}