/******************************************************************************* * Copyright (c) 2017 the TeXlipse team and others. * 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: * The TeXlipse team - initial API and implementation *******************************************************************************/ package org.eclipse.texlipse.editor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.link.LinkedModeModel; import org.eclipse.jface.text.link.LinkedModeUI; import org.eclipse.jface.text.link.LinkedPosition; import org.eclipse.jface.text.link.LinkedPositionGroup; import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags; import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.texlipse.TexlipsePlugin; import org.eclipse.texlipse.model.TexCommandEntry; import org.eclipse.texlipse.properties.TexlipseProperties; import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; /** * This class is a wrapper class to create an ICompletionProposal * from a TexCommandEntry. It also creates "smart" braces. * * @author Boris von Loesch * @author Oskar Ojala * */ public class TexCompletionProposal implements ICompletionProposal { private TexCommandEntry fentry; private int fReplacementOffset; private int fReplacementLength; private ISourceViewer fviewer; /** * Constructs a new completion proposal for a (La)TeX command * * @param entry The command entry * @param replacementOffset Offset of where it is to be replaced * @param replacementLength The length of the replacement * @param viewer The current viewer */ public TexCompletionProposal(TexCommandEntry entry, int replacementOffset, int replacementLength, ISourceViewer viewer) { fentry = entry; fReplacementLength = replacementLength; fReplacementOffset = replacementOffset; fviewer = viewer; } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument) */ public void apply(IDocument document) { try { if (fentry.arguments > 0) { StringBuffer displayKey = new StringBuffer(fentry.key); for (int j=0; j < fentry.arguments; j++) displayKey.append("{}"); document.replace(fReplacementOffset, fReplacementLength, displayKey.toString()); if (TexlipsePlugin.getDefault().getPreferenceStore() .getBoolean(TexlipseProperties.SMART_PARENS)){ LinkedModeModel model= new LinkedModeModel(); for (int j=0; j < fentry.arguments; j++){ int newOffset = fReplacementOffset + fentry.key.length() + j*2 + 1; LinkedPositionGroup group = new LinkedPositionGroup(); group.addPosition(new LinkedPosition(document, newOffset, 0, LinkedPositionGroup.NO_STOP)); model.addGroup(group); } model.forceInstall(); LinkedModeUI ui = new EditorLinkedModeUI(model, fviewer); ui.setSimpleMode(false); ui.setExitPolicy(new ExitPolicy('}', fviewer)); ui.setExitPosition(fviewer, fReplacementOffset + displayKey.length(), 0, Integer.MAX_VALUE); ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER); ui.enter(); } } else { document.replace(fReplacementOffset, fReplacementLength, fentry.key); } } catch (BadLocationException x) { } } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument) */ public Point getSelection(IDocument document) { if (fentry.arguments > 0) return new Point(fReplacementOffset + fentry.key.length()+1, 0); return new Point(fReplacementOffset + fentry.key.length(), 0); } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() */ public String getAdditionalProposalInfo() { return (fentry.info.length() > TexCompletionProcessor.assistLineLength ? TexCompletionProcessor.wrapString(fentry.info, TexCompletionProcessor.assistLineLength) : fentry.info); } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString() */ public String getDisplayString() { return fentry.key; } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage() */ public Image getImage() { return fentry.getImage(); } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation() */ public IContextInformation getContextInformation() { return null; } protected static class ExitPolicy implements IExitPolicy { final char fExitCharacter; ISourceViewer fviewer; public ExitPolicy(char exitCharacter, ISourceViewer viewer) { fExitCharacter= exitCharacter; fviewer = viewer; } /* * @see org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int) */ public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event, int offset, int length) { if (event.character == fExitCharacter) { try { if (fviewer.getDocument().getChar(offset) == fExitCharacter) { event.doit = false; } try { if (fviewer.getDocument().getChar(offset + 1) == '{') { fviewer.setSelectedRange(offset + 2, 0); } else { fviewer.setSelectedRange(offset + 1, 0); } return null; } catch (BadLocationException e) { } fviewer.setSelectedRange(offset + 1, 0); } catch (BadLocationException e1) { // Should not happen } } else if (event.character == '{') { try { if (fviewer.getDocument().getChar(offset - 1) == '{') event.doit = false; } catch (BadLocationException e) { } } return null; } } }