/******************************************************************************* * Copyright (c) 2016 Pivotal, Inc. * 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: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.properties.editor.yaml.reconcile; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.springframework.ide.eclipse.boot.properties.editor.completions.LazyProposalApplier; import org.springframework.ide.eclipse.boot.properties.editor.metadata.PropertyInfo; import org.springframework.ide.eclipse.boot.properties.editor.reconciling.ProblemFixer; import org.springframework.ide.eclipse.boot.properties.editor.reconciling.SpringPropertyProblem; import org.springframework.ide.eclipse.boot.util.Log; import org.springframework.ide.eclipse.editor.support.completions.DocumentEdits; import org.springframework.ide.eclipse.editor.support.completions.ProposalApplier; import org.springframework.ide.eclipse.editor.support.reconcile.QuickfixContext; import org.springframework.ide.eclipse.editor.support.yaml.YamlDocument; import org.springframework.ide.eclipse.editor.support.yaml.completions.YamlPathEdits; import org.springframework.ide.eclipse.editor.support.yaml.path.YamlPath; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SChildBearingNode; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SDocNode; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SKeyNode; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SNode; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SNodeType; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureProvider; @SuppressWarnings("restriction") public class ReplaceDeprecatedYamlQuickfix implements ICompletionProposal { public static ProblemFixer FIXER = (context, problem, proposals) -> { PropertyInfo metadata = problem.getMetadata(); if (metadata!=null) { String replacement = metadata.getDeprecationReplacement(); if (replacement!=null) { //No need to check problem type... we only attach this fixer to problems of applicable type. proposals.add(new ReplaceDeprecatedYamlQuickfix(context, problem)); } } }; private final QuickfixContext context; private final SpringPropertyProblem problem; private LazyProposalApplier applier = new LazyProposalApplier() { protected ProposalApplier create() throws Exception { String newName = problem.getMetadata().getDeprecationReplacement(); String oldName = problem.getPropertyName(); YamlPath newPath = YamlPath.fromProperty(newName); YamlPath oldPath = YamlPath.fromProperty(oldName); YamlPath prefix = newPath.commonPrefix(oldPath); if (prefix.size()==newPath.size()-1 && newPath.size()==oldPath.size()) { //only the last segment has changed. We can do a simple 'in-place' replace // of just the change segment. DocumentEdits edits = new DocumentEdits(context.getDocument()); edits.replace(problem.getOffset(), problem.getEnd(), newPath.getLastSegment().toPropString()); return edits; } YamlDocument doc = new YamlDocument(context.getDocument(), YamlStructureProvider.DEFAULT); SNode problemNode = doc.getStructure().find(problem.getOffset()); if (problemNode.getNodeType()==SNodeType.KEY) { SKeyNode problemKey = (SKeyNode) problemNode; if (problemKey.isInKey(problem.getOffset())) { YamlPathEdits edits = new YamlPathEdits(doc); // print(doc, edits); String valueText = problemKey.getValueWithRelativeIndent(); edits.deleteNode(problemKey); int maxParentDeletions = oldPath.size() - prefix.size() - 1; // don't delete bits of the common prefix! SChildBearingNode parent = problemNode.getParent(); while (maxParentDeletions>0 && parent!=null && parent.getChildren().size()==1) { edits.deleteNode(parent); parent = parent.getParent(); maxParentDeletions--; } // print(doc, edits); SDocNode docRoot = problemNode.getDocNode(); //edits should stay within the same 'document' for yaml file that has multiple documents inside of it. edits.createPath(docRoot, YamlPath.fromProperty(newName), valueText); // print(doc, edits); return edits; } } //Not sure what to do... case not covered... so do nothing but tell the user. context.getUI().error("Yaml file too complex", "Sorry, but the yaml file is too complex for this quickfix. " + "Please make the change manually." ); return ProposalApplier.NULL; } // private void print(YamlDocument doc, YamlPathEdits edits) throws Exception { // Document workingCopy = new Document(doc.getDocument().get()); // edits.apply(workingCopy); // System.out.println("=============="); // System.out.println(workingCopy.get()); // System.out.println("=============="); // } }; public ReplaceDeprecatedYamlQuickfix(QuickfixContext context, SpringPropertyProblem problem) { this.context = context; this.problem = problem; } @Override public void apply(IDocument doc) { try { applier.apply(doc); } catch (Exception e) { Log.log(e); } } private String getReplacementProperty() { return problem.getMetadata().getDeprecationReplacement(); } @Override public Point getSelection(IDocument doc) { try { return applier.getSelection(doc); } catch (Exception e) { Log.log(e); return null; } } @Override public String getAdditionalProposalInfo() { return null; } @Override public String getDisplayString() { return "Change to '"+getReplacementProperty()+"'"; } @Override public Image getImage() { return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); } @Override public IContextInformation getContextInformation() { return null; } }