/******************************************************************************* * 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; } }