/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.internal.text.correction; import com.google.common.collect.Lists; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.ui.DartToolsPlugin; import com.google.dart.tools.ui.internal.text.editor.DartEditor; import org.dartlang.analysis.server.protocol.AnalysisError; import org.dartlang.analysis.server.protocol.Location; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; import org.eclipse.jface.text.quickassist.QuickAssistAssistant; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; import java.util.List; /** * @coverage dart.editor.ui.correction */ public class DartCorrectionAssistant_NEW extends QuickAssistAssistant { private static IRegion getRegionOfInterest(ITextEditor editor, int invocationLocation) throws BadLocationException { IDocumentProvider documentProvider = editor.getDocumentProvider(); if (documentProvider == null) { return null; } IDocument document = documentProvider.getDocument(editor.getEditorInput()); if (document == null) { return null; } return document.getLineInformationOfOffset(invocationLocation); } private static boolean isInside(int offset, int start, int end) { // make sure to handle 0-length ranges return offset == start || offset == end || offset > start && offset < end; } private final DartEditor editor; private ITextViewer viewer; /** * The {@link AnalysisError} to propose fixes for. */ private AnalysisError problemToFix; public DartCorrectionAssistant_NEW(ITextEditor editor) { Assert.isNotNull(editor); if (editor instanceof DartEditor) { this.editor = (DartEditor) editor; DartCorrectionProcessor_NEW processor = new DartCorrectionProcessor_NEW(this); setQuickAssistProcessor(processor); } else { this.editor = null; } setInformationControlCreator(getInformationControlCreator()); } /** * @return the underlying {@link DartEditor}. */ public DartEditor getEditor() { return editor; } /** * @return the {@link AnalysisError} to compute fixes for. */ public AnalysisError getProblemToFix() { return problemToFix; } @Override public void install(ISourceViewer sourceViewer) { super.install(sourceViewer); this.viewer = sourceViewer; } /** * Show completions at caret position. If current position does not contain quick fixes look for * next quick fix on same line by moving from left to right and restarting at end of line if the * beginning of the line is reached. * * @see IQuickAssistAssistant#showPossibleQuickAssists() */ @Override public String showPossibleQuickAssists() { prepareProblemsAtCaretLocation(); return super.showPossibleQuickAssists(); } public void showProblemToFix() { if (problemToFix == null) { return; } int offset = problemToFix.getLocation().getOffset(); viewer.setSelectedRange(offset, 0); viewer.revealRange(offset, 0); } /** * @return the {@link IInformationControlCreator} used to display prefix and help user to decide * which correction to choose. */ private IInformationControlCreator getInformationControlCreator() { return new IInformationControlCreator() { @Override public IInformationControl createInformationControl(Shell parent) { return new DefaultInformationControl( parent, DartToolsPlugin.getAdditionalInfoAffordanceString()); } }; } /** * Fills {@link #problemToFix}. */ private void prepareProblemsAtCaretLocation() { problemToFix = null; try { Point selectedRange = viewer.getSelectedRange(); int currOffset = selectedRange.x; // prepare file String file = editor.getInputFilePath(); if (file == null) { return; } // prepare errors AnalysisError[] errors = DartCore.getAnalysisServerData().getErrors(file); // prepare current line range IRegion lineInfo = getRegionOfInterest(editor, currOffset); if (lineInfo == null) { return; } int rangeStart = lineInfo.getOffset(); int rangeEnd = rangeStart + lineInfo.getLength(); // prepare fixable problems on the current line List<AnalysisError> allProblems = Lists.newArrayList(); List<Position> allPositions = Lists.newArrayList(); for (AnalysisError error : errors) { Location location = error.getLocation(); Position pos = new Position(location.getOffset(), location.getLength()); // check that error is on the current line if (!isInside(pos.offset, rangeStart, rangeEnd)) { continue; } // add only if has fix if (QuickFixProcessor_NEW.hasFix(error)) { allProblems.add(error); allPositions.add(pos); } } // problem under caret for (int i = 0; i < allPositions.size(); i++) { Position pos = allPositions.get(i); if (pos.includes(currOffset)) { problemToFix = allProblems.get(i); break; } } // problem after caret if (problemToFix == null) { int bestOffset = Integer.MAX_VALUE; for (int i = 0; i < allPositions.size(); i++) { Position pos = allPositions.get(i); if (pos.offset > currOffset) { int offset = pos.offset - currOffset; if (offset < bestOffset) { bestOffset = offset; problemToFix = allProblems.get(i); } } } } // problem before caret if (problemToFix == null) { int bestOffset = Integer.MAX_VALUE; for (int i = 0; i < allPositions.size(); i++) { Position pos = allPositions.get(i); if (pos.offset < currOffset) { int offset = currOffset - pos.offset; if (offset < bestOffset) { bestOffset = offset; problemToFix = allProblems.get(i); } } } } // not found if (problemToFix == null) { return; } } catch (Throwable e) { DartToolsPlugin.log(e); } } }