/** * Copyright (c) 2013-2016 Angelo ZERR and Genuitec LLC. * 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: * Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation * Piotr Tomiak <piotr@genuitec.com> - refactoring of file management API * - asynchronous file upload * - partial file upload */ package tern.eclipse.ide.internal.core.resources; import java.io.IOException; import org.eclipse.core.resources.IFile; import org.eclipse.jface.text.IDocument; import com.eclipsesource.json.JsonValue; import tern.ITernFile; import tern.ITernProject; import tern.resources.ITernFileUploader; import tern.resources.TernFileSynchronizer; import tern.server.protocol.TernDoc; import tern.server.protocol.TernFile; import tern.server.protocol.TernQuery; /** * Extension of {@link TernFileManager} to works with Eclipse {@link IFile} * */ public class IDETernFileSynchronizer extends TernFileSynchronizer { protected static final int BIG_FILE = 500; /** * Constructor of file manager with the owner Eclipse project. */ public IDETernFileSynchronizer(ITernProject project) { super(project); } @Override protected ITernFileUploader createTernFileUploader() { return new IDETernFileUploader(getProject()); } @Override protected void addJSFile(TernDoc doc, ITernFile file) throws IOException { TernQuery query = doc.getQuery(); String fileName = file.getFullName(getProject()); query.setFile(fileName); IDocument document = (IDocument) file.getAdapter(IDocument.class); //include file as a part of the tern doc if (document != null) { String text = document.get(); String oldText = getSentFileContent(fileName); if (text.equals(oldText)) { if (!getTernFileUploader().cancel(fileName)) { //no need to synchronize as file has already been sent to the server return; } //continue to include a whole file in the request } else if (oldText != null && //do partial content assist only in big files document.getNumberOfLines() > BIG_FILE) { try { int start; for (start = 0; start < text.length() && start < oldText.length() && text.charAt(start) == oldText.charAt(start); start++); int end; int offset = oldText.length() - text.length(); for (end = text.length() - 1; end > 0 && end + offset > 0 && text.charAt(end) == oldText.charAt(end + offset); end--); int startLine = document.getLineOfOffset(start); int endLine = document.getLineOfOffset(end); int selEndLine; if (query.get("end") != null) { //$NON-NLS-1$ selEndLine = document.getLineOfOffset(query.get("end").asInt()); //$NON-NLS-1$ } else { selEndLine = -1; } int selStartLine; if (query.get("start") != null) { //$NON-NLS-1$ selStartLine = document.getLineOfOffset(query.get("start").asInt()); //$NON-NLS-1$ } else { selStartLine = selEndLine; } if (startLine <= endLine && endLine - startLine < 100 && //Selection should be part of modified lines. //Tolerate 2 lines before and 2 lines after. !(selStartLine-2 > endLine || selEndLine+2 < startLine)) { startLine -= 50; if (startLine < 0) { startLine = 0; } endLine += 20; if (endLine >= document.getNumberOfLines()) { endLine = document.getNumberOfLines() - 1; } start = document.getLineOffset(startLine); end = document.getLineOffset(endLine); String textPart = document.get(start, end-start); doc.addFile(new TernFile(fileName, textPart, null, start)); query.setFile("#" + (doc.getFiles().size() - 1)); //$NON-NLS-1$ JsonValue val = query.get("end"); //$NON-NLS-1$ if (val != null) { query.setEnd(val.asInt() - start); } val = query.get("start"); //$NON-NLS-1$ if (val != null) { query.add("start", val.asInt() - start); //$NON-NLS-1$ } //all's fine - return return; } } catch (Exception e) { getProject().handleException(e); } } } //fallback - include whole file in the request TernFile tf = file.toTernServerFile(getProject()); doc.addFile(tf); } }