| /*=============================================================================# |
| # Copyright (c) 2005, 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.r.ui.editors.templates; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.templates.TemplateContextType; |
| import org.eclipse.jface.text.templates.TemplateVariable; |
| import org.eclipse.text.edits.DeleteEdit; |
| import org.eclipse.text.edits.InsertEdit; |
| import org.eclipse.text.edits.MultiTextEdit; |
| import org.eclipse.text.edits.ReplaceEdit; |
| import org.eclipse.text.edits.TextEdit; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.text.core.TextRegion; |
| import org.eclipse.statet.jcommons.text.core.input.StringParserInput; |
| |
| import org.eclipse.statet.ecommons.text.IndentUtil; |
| import org.eclipse.statet.ecommons.text.IndentUtil.IndentEditAction; |
| |
| import org.eclipse.statet.internal.r.ui.RUIPlugin; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor; |
| import org.eclipse.statet.ltk.ui.templates.SourceEditorTemplateContext; |
| import org.eclipse.statet.r.core.IRCoreAccess; |
| import org.eclipse.statet.r.core.RCodeStyleSettings; |
| import org.eclipse.statet.r.core.RCore; |
| import org.eclipse.statet.r.core.rlang.RTerminal; |
| import org.eclipse.statet.r.core.rlang.RTokens; |
| import org.eclipse.statet.r.core.rsource.RLexer; |
| import org.eclipse.statet.r.ui.editors.IRSourceEditor; |
| |
| |
| @NonNullByDefault |
| public class REditorContext extends SourceEditorTemplateContext { |
| |
| |
| public REditorContext(final TemplateContextType type, final IDocument document, |
| final TextRegion region, |
| final ISourceEditor editor, final int flags) { |
| super(type, document, region, editor, flags); |
| } |
| |
| |
| protected IRCoreAccess getRCoreAccess() { |
| final ISourceEditor editor= getEditor(); |
| return (editor instanceof IRSourceEditor) ? |
| ((IRSourceEditor) editor).getRCoreAccess() : |
| RCore.WORKBENCH_ACCESS; |
| } |
| |
| @Override |
| public void setVariable(final String name, @Nullable String value) { |
| if (SELECTION_VAR_NAME.equals(name) && value != null && value.length() > 0) { |
| try { |
| final IDocument valueDoc = new Document(value); |
| |
| final IndentUtil util = new IndentUtil(valueDoc, getRCoreAccess().getRCodeStyle()); |
| final int column = util.getMultilineIndentColumn(0, valueDoc.getNumberOfLines()-1); |
| if (column > 0) { |
| final IndentEditAction action = new IndentEditAction(column) { |
| @Override |
| public void doEdit(final int line, final int offset, final int length, final StringBuilder text) |
| throws BadLocationException { |
| TextEdit edit; |
| if (text != null) { |
| final int position = util.getIndentedOffsetAt(text, column); |
| edit = new ReplaceEdit(offset, length, text.substring(position, text.length())); |
| } |
| else { |
| final int end = util.getIndentedOffsetAt(line, column); |
| edit = new DeleteEdit(offset, end-offset); |
| } |
| edit.apply(valueDoc, 0); |
| } |
| }; |
| util.editInIndent(0, valueDoc.getNumberOfLines()-1, action); |
| setVariable(INDENTATION_VAR_NAME, util.createIndentString(column)); |
| value = valueDoc.get(); |
| } |
| } |
| catch (final BadLocationException e) { |
| RUIPlugin.logError(RUIPlugin.INTERNAL_ERROR, "An error occurred while computing indentation variable for R editor templates.", e); //$NON-NLS-1$ |
| } |
| } |
| super.setVariable(name, value); |
| } |
| |
| @Override |
| protected void format(final MultiTextEdit root, final IDocument templateDoc, |
| final TemplateVariable[] variables, final IDocument baseDoc) |
| throws BadLocationException { |
| indent(root, templateDoc, variables, baseDoc); |
| |
| if ((getFlags() & FORMAT_START) != 0 && getVariable(INDENTATION_VAR_NAME) == null |
| && getStart() > 0 && !RTokens.isWhitespace(baseDoc.getChar(getStart() - 1)) |
| && templateDoc.getLength() > 0 && !RTokens.isWhitespace(templateDoc.getChar(0)) ) { |
| final String line= templateDoc.get(0, templateDoc.getLineLength(0)); |
| final RLexer lexer= new RLexer(); |
| lexer.reset(new StringParserInput(line).init()); |
| final RCodeStyleSettings rCodeStyle= getRCoreAccess().getRCodeStyle(); |
| |
| final RTerminal token= lexer.next(); |
| if (getSpaceBefore(token, rCodeStyle)) { |
| root.addChild(new InsertEdit(0, " ")); //$NON-NLS-1$ |
| } |
| |
| if (variables.length == 0 && line.length() == templateDoc.getLength() |
| && lexer.next() == RTerminal.EOF |
| && getSpaceAfter(token, rCodeStyle) ) { |
| root.addChild(new InsertEdit(line.length(), " ")); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| protected boolean getSpaceBefore(final RTerminal terminal, final RCodeStyleSettings rCodeStyle) { |
| switch (terminal) { |
| case EQUAL: |
| return rCodeStyle.getWhitespaceArgAssignBefore(); |
| |
| case ARROW_LEFT_S: |
| case ARROW_LEFT_D: |
| return rCodeStyle.getWhitespaceAssignBefore(); |
| |
| case ARROW_RIGHT_S: |
| case ARROW_RIGHT_D: |
| return rCodeStyle.getWhitespaceArgAssignAfter(); |
| |
| case PLUS: |
| case MINUS: |
| case MULT: |
| case DIV: |
| case OR: |
| case OR_D: |
| case AND: |
| case AND_D: |
| case NOT: |
| case POWER: |
| case SEQ: |
| case SPECIAL: |
| case COLON_EQUAL: |
| case TILDE: |
| case REL_NE: |
| case REL_EQ: |
| case REL_LT: |
| case REL_LE: |
| case REL_GT: |
| case REL_GE: |
| return rCodeStyle.getWhitespaceOtherOpBefore(); |
| |
| default: |
| return true; |
| } |
| } |
| |
| protected boolean getSpaceAfter(final RTerminal terminal, final RCodeStyleSettings rCodeStyle) { |
| switch (terminal) { |
| case EQUAL: |
| return rCodeStyle.getWhitespaceArgAssignAfter(); |
| |
| case ARROW_LEFT_S: |
| case ARROW_LEFT_D: |
| return rCodeStyle.getWhitespaceAssignAfter(); |
| |
| case ARROW_RIGHT_S: |
| case ARROW_RIGHT_D: |
| return rCodeStyle.getWhitespaceArgAssignBefore(); |
| |
| case PLUS: |
| case MINUS: |
| case MULT: |
| case DIV: |
| case OR: |
| case OR_D: |
| case AND: |
| case AND_D: |
| case NOT: |
| case POWER: |
| case SEQ: |
| case SPECIAL: |
| case COLON_EQUAL: |
| case TILDE: |
| case REL_NE: |
| case REL_EQ: |
| case REL_LT: |
| case REL_LE: |
| case REL_GT: |
| case REL_GE: |
| return rCodeStyle.getWhitespaceOtherOpAfter(); |
| |
| default: |
| return true; |
| } |
| } |
| |
| } |