| /*=============================================================================# |
| # Copyright (c) 2012, 2019 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.internal.docmlet.tex.ui.sourceediting; |
| |
| import static org.eclipse.statet.docmlet.tex.core.source.LtxHeuristicTokenScanner.CURLY_BRACKET_TYPE; |
| import static org.eclipse.statet.docmlet.tex.core.source.LtxHeuristicTokenScanner.PARATHESIS_TYPE; |
| import static org.eclipse.statet.docmlet.tex.core.source.LtxHeuristicTokenScanner.SQUARE_BRACKET_TYPE; |
| import static org.eclipse.statet.docmlet.tex.core.source.TexDocumentConstants.LTX_ANY_CONTENT_CONSTRAINT; |
| import static org.eclipse.statet.docmlet.tex.core.source.TexDocumentConstants.LTX_DEFAULT_CONTENT_CONSTRAINT; |
| import static org.eclipse.statet.docmlet.tex.core.source.TexDocumentConstants.LTX_DEFAULT_OR_MATH_CONTENT_CONSTRAINT; |
| import static org.eclipse.statet.ecommons.text.ui.BracketLevel.AUTODELETE; |
| |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jface.text.AbstractDocument; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.BadPartitioningException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.DocumentCommand; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.ITypedRegion; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.TextUtilities; |
| 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.swt.events.KeyEvent; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.text.edits.TextEdit; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.text.core.TextRegion; |
| import org.eclipse.statet.jcommons.text.core.input.StringParserInput; |
| import org.eclipse.statet.jcommons.text.core.input.TextParserInput; |
| |
| import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess; |
| import org.eclipse.statet.ecommons.text.BasicHeuristicTokenScanner; |
| import org.eclipse.statet.ecommons.text.IIndentSettings; |
| import org.eclipse.statet.ecommons.text.ITokenScanner; |
| import org.eclipse.statet.ecommons.text.TextUtil; |
| import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartition; |
| import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionNode; |
| import org.eclipse.statet.ecommons.ui.ISettingsChangedHandler; |
| |
| import org.eclipse.statet.docmlet.tex.core.TexCodeStyleSettings; |
| import org.eclipse.statet.docmlet.tex.core.TexCoreAccess; |
| import org.eclipse.statet.docmlet.tex.core.ast.LtxParser; |
| import org.eclipse.statet.docmlet.tex.core.ast.SourceComponent; |
| import org.eclipse.statet.docmlet.tex.core.parser.NowebLtxLexer; |
| import org.eclipse.statet.docmlet.tex.core.refactoring.LtxSourceIndenter; |
| import org.eclipse.statet.docmlet.tex.core.source.LtxHeuristicTokenScanner; |
| import org.eclipse.statet.docmlet.tex.core.source.LtxPartitionNodeType; |
| import org.eclipse.statet.docmlet.tex.core.source.TexDocumentConstants; |
| import org.eclipse.statet.docmlet.tex.ui.sourceediting.TexEditingSettings; |
| import org.eclipse.statet.internal.docmlet.tex.ui.editors.HardLineWrap; |
| import org.eclipse.statet.ltk.ui.sourceediting.AbstractAutoEditStrategy; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISmartInsertSettings; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor; |
| |
| |
| /** |
| * Auto edit strategy for TeX code |
| */ |
| public class LtxAutoEditStrategy extends AbstractAutoEditStrategy { |
| |
| |
| public static class Settings implements ISmartInsertSettings, ISettingsChangedHandler { |
| |
| private final TexCoreAccess coreAccess; |
| |
| private boolean enabledByDefault; |
| private TabAction tabAction; |
| private boolean closeBrackets; |
| private boolean closeParenthesis; |
| private boolean closeMathDollar; |
| |
| private boolean hardWrapText; |
| |
| |
| public Settings(final TexCoreAccess coreAccess) { |
| this.coreAccess= coreAccess; |
| updateSettings(); |
| } |
| |
| |
| @Override |
| public void handleSettingsChanged(final Set<String> groupIds, final Map<String, Object> options) { |
| if (groupIds == null || groupIds.contains(TexEditingSettings.SMARTINSERT_GROUP_ID)) { |
| updateSettings(); |
| } |
| } |
| |
| private void updateSettings() { |
| final PreferenceAccess prefs= this.coreAccess.getPrefs(); |
| this.enabledByDefault= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_BYDEFAULT_ENABLED_PREF); |
| this.tabAction= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_TAB_ACTION_PREF); |
| this.closeBrackets= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_CLOSEBRACKETS_ENABLED_PREF); |
| this.closeParenthesis= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_CLOSEPARENTHESIS_ENABLED_PREF); |
| this.closeMathDollar= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_CLOSEMATHDOLLAR_ENABLED_PREF); |
| this.hardWrapText= prefs.getPreferenceValue(TexEditingSettings.SMARTINSERT_HARDWRAP_TEXT_ENABLED_PREF); |
| } |
| |
| @Override |
| public boolean isSmartInsertEnabledByDefault() { |
| return this.enabledByDefault; |
| } |
| |
| @Override |
| public TabAction getSmartInsertTabAction() { |
| return this.tabAction; |
| } |
| |
| } |
| |
| |
| private static final StringParserInput DEFAULT_PARSER_INPUT= new StringParserInput(); |
| |
| |
| private final TexCoreAccess texCoreAccess; |
| private final Settings settings; |
| |
| private LtxHeuristicTokenScanner scanner; |
| private TexCodeStyleSettings texCodeStyle; |
| private LtxSourceIndenter indenter; |
| |
| private final HardLineWrap hardLineWrap; |
| |
| |
| public LtxAutoEditStrategy(final TexCoreAccess coreAccess, final ISourceEditor editor) { |
| super(editor); |
| assert (coreAccess != null); |
| |
| this.texCoreAccess= coreAccess; |
| this.settings= new Settings(coreAccess); |
| this.hardLineWrap= new HardLineWrap(); |
| } |
| |
| |
| @Override |
| public Settings getSettings() { |
| return this.settings; |
| } |
| |
| @Override |
| protected IIndentSettings getCodeStyleSettings() { |
| return this.texCodeStyle; |
| } |
| |
| |
| @Override |
| protected final TreePartition initCustomization(final int offset, final int ch) |
| throws BadLocationException, BadPartitioningException { |
| if (this.scanner == null) { |
| this.scanner= createScanner(); |
| } |
| this.texCodeStyle= this.texCoreAccess.getTexCodeStyle(); |
| |
| return super.initCustomization(offset, ch); |
| } |
| |
| protected LtxHeuristicTokenScanner createScanner() { |
| return LtxHeuristicTokenScanner.create(getDocumentContentInfo()); |
| } |
| |
| @Override |
| protected TextRegion computeValidRange(final int offset, final TreePartition partition, final int ch) { |
| TreePartitionNode node= partition.getTreeNode(); |
| if (node.getType() instanceof LtxPartitionNodeType) { |
| if (getDocumentContentInfo().getPrimaryType() == TexDocumentConstants.LTX_PARTITIONING) { |
| return super.computeValidRange(offset, partition, ch); |
| } |
| else { |
| TreePartitionNode parent; |
| while ((parent= node.getParent()) != null |
| && parent.getType() instanceof LtxPartitionNodeType) { |
| node= parent; |
| } |
| return node; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| protected BasicHeuristicTokenScanner getScanner() { |
| return this.scanner; |
| } |
| |
| @Override |
| protected final void quitCustomization() { |
| super.quitCustomization(); |
| |
| this.texCodeStyle= null; |
| } |
| |
| |
| private final boolean isClosedBracket(final int backwardOffset, final int forwardOffset, |
| final String currentPartition, final int searchType) { |
| int[] balance= new int[3]; |
| balance[searchType]++; |
| this.scanner.configure(getDocument(), currentPartition); |
| balance= this.scanner.computeBracketBalance(backwardOffset, forwardOffset, balance, searchType); |
| return (balance[searchType] <= 0); |
| } |
| |
| private boolean isValueChar(final int offset) throws BadLocationException { |
| final int ch= getChar(offset); |
| return (ch != -1 && Character.isLetterOrDigit(ch)); |
| } |
| |
| |
| @Override |
| protected char isCustomizeKey(final KeyEvent event) { |
| switch (event.character) { |
| case '{': |
| case '(': |
| case '[': |
| case '$': |
| return event.character; |
| case '\t': |
| if (event.stateMask == 0) { |
| return '\t'; |
| } |
| break; |
| case 0x0A: |
| case 0x0D: |
| if (getEditor3() != null) { |
| return '\n'; |
| } |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| @Override |
| protected void doCustomizeKeyCommand(final char ch, final DocumentCommand command, |
| final TreePartition partition) throws Exception { |
| final String contentType= partition.getType(); |
| final int cEnd= command.offset+command.length; |
| int linkedModeType= -1; |
| int linkedModeOffset= -1; |
| |
| KEY: switch (ch) { |
| case '\t': |
| if (LTX_ANY_CONTENT_CONSTRAINT.matches(contentType) |
| && isRegularTabCommand(command) ) { |
| command.text= "\t"; //$NON-NLS-1$ |
| smartInsertOnTab(command, |
| (contentType != TexDocumentConstants.LTX_VERBATIM_CONTENT_TYPE) ); |
| break KEY; |
| } |
| return; |
| case '{': |
| if (LTX_DEFAULT_OR_MATH_CONTENT_CONSTRAINT.matches(contentType) |
| && !LtxHeuristicTokenScanner.isEscaped(getDocument(), command.offset) ) { |
| command.text= "{"; //$NON-NLS-1$ |
| if (this.settings.closeBrackets && !isValueChar(cEnd)) { |
| if (!isClosedBracket(command.offset, cEnd, contentType, CURLY_BRACKET_TYPE)) { |
| command.text= "{}"; //$NON-NLS-1$ |
| linkedModeType= 2 | AUTODELETE; |
| } |
| else if (getChar(cEnd) == '}') { |
| linkedModeType= 2; |
| } |
| } |
| break KEY; |
| } |
| return; |
| case '[': |
| if (LTX_DEFAULT_OR_MATH_CONTENT_CONSTRAINT.matches(contentType) |
| && !LtxHeuristicTokenScanner.isEscaped(getDocument(), command.offset) ) { |
| command.text= "["; //$NON-NLS-1$ |
| if (this.settings.closeBrackets && !isValueChar(cEnd)) { |
| if (!isClosedBracket(command.offset, cEnd, contentType, SQUARE_BRACKET_TYPE)) { |
| command.text= "[]"; //$NON-NLS-1$ |
| linkedModeType= 2 | AUTODELETE; |
| } |
| else if (getChar(cEnd) == ']') { |
| linkedModeType= 2; |
| } |
| } |
| break KEY; |
| } |
| return; |
| case '(': |
| if (LTX_DEFAULT_OR_MATH_CONTENT_CONSTRAINT.matches(contentType) |
| && !LtxHeuristicTokenScanner.isEscaped(getDocument(), command.offset) ) { |
| command.text= "("; //$NON-NLS-1$ |
| if (this.settings.closeParenthesis && !isValueChar(cEnd)) { |
| if (!isClosedBracket(command.offset, cEnd, contentType, PARATHESIS_TYPE)) { |
| command.text= "()"; //$NON-NLS-1$ |
| linkedModeType= 2 | AUTODELETE; |
| } |
| else if (getChar(cEnd) == ')') { |
| linkedModeType= 2; |
| } |
| } |
| break KEY; |
| } |
| return; |
| case '$': |
| if (contentType == TexDocumentConstants.LTX_MATH_CONTENT_TYPE |
| && !LtxHeuristicTokenScanner.isEscaped(getDocument(), command.offset) ) { |
| command.text= "$"; //$NON-NLS-1$ |
| if (this.settings.closeMathDollar |
| && partition.getOffset() == command.offset - 1 |
| && getChar(command.offset - 1) == '$' |
| && TextUtil.countForward(getDocument(), cEnd, '$') == 1) { |
| command.text= "$$"; //$NON-NLS-1$ |
| linkedModeType= 3 | AUTODELETE; |
| break KEY; |
| } |
| } |
| if ((LTX_DEFAULT_CONTENT_CONSTRAINT.matches(contentType)) |
| && !LtxHeuristicTokenScanner.isEscaped(getDocument(), command.offset) ) { |
| command.text= "$"; //$NON-NLS-1$ |
| if (this.settings.closeMathDollar && !isValueChar(cEnd)) { |
| command.text= "$$"; //$NON-NLS-1$ |
| linkedModeType= 2 | AUTODELETE; |
| } |
| break KEY; |
| } |
| return; |
| case '\n': |
| if (LTX_DEFAULT_OR_MATH_CONTENT_CONSTRAINT.matches(contentType) |
| || contentType == TexDocumentConstants.LTX_COMMENT_CONTENT_TYPE ) { |
| command.text= TextUtilities.getDefaultLineDelimiter(getDocument()); |
| smartIndentOnNewLine(command); |
| break KEY; |
| } |
| return; |
| default: |
| assert (false); |
| return; |
| } |
| |
| if (command.doit && command.text.length() > 0 && getEditor().isEditable(true)) { |
| getViewer().getTextWidget().setRedraw(false); |
| try { |
| applyCommand(command); |
| updateSelection(command); |
| |
| if (linkedModeType >= 0) { |
| if (linkedModeOffset < 0) { |
| linkedModeOffset= command.offset; |
| } |
| createLinkedMode(linkedModeOffset, ch, linkedModeType).enter(); |
| } |
| } |
| finally { |
| getViewer().getTextWidget().setRedraw(true); |
| } |
| } |
| } |
| |
| @Override |
| protected void doCustomizeOtherCommand(final DocumentCommand command, final TreePartition partition) |
| throws Exception { |
| final String contentType= partition.getType(); |
| |
| if (LTX_DEFAULT_CONTENT_CONSTRAINT.matches(contentType)) { |
| if (command.length == 0 && TextUtilities.equals(getDocument().getLegalLineDelimiters(), command.text) != -1) { |
| smartIndentOnNewLine(command); |
| } |
| else if (this.settings.hardWrapText && command.length == 0) { |
| smartLineWrap(command); |
| } |
| } |
| } |
| |
| |
| private void smartIndentOnNewLine(final DocumentCommand command) throws Exception { |
| final AbstractDocument doc= getDocument(); |
| final IRegion line= doc.getLineInformationOfOffset(command.offset); |
| int backward= command.offset; |
| final ITypedRegion partition= doc.getPartition(getDocumentContentInfo().getPartitioning(), |
| backward, true ); |
| if (partition.getType() == TexDocumentConstants.LTX_COMMENT_CONTENT_TYPE |
| || partition.getType() == TexDocumentConstants.LTX_MATHCOMMENT_CONTENT_TYPE) { |
| backward= partition.getOffset(); |
| } |
| int forward; |
| this.scanner.configure(doc); |
| if (backward >= line.getOffset() |
| && (forward= this.scanner.findAnyNonBlankForward(command.offset + command.length, ITokenScanner.UNBOUND, false)) != ITokenScanner.NOT_FOUND |
| && forward + 6 < doc.getLength() |
| && doc.get(forward, 4).equals("\\end") //$NON-NLS-1$ |
| && (backward= this.scanner.findAnyNonBlankBackward(backward, line.getOffset(), false)) != ITokenScanner.NOT_FOUND |
| && doc.getChar(backward) == '}' |
| && (backward= this.scanner.scanBackward(backward, line.getOffset() - 1, '\\')) != ITokenScanner.NOT_FOUND |
| && (backward == 0 || doc.getChar(backward - 1) != '\\') |
| && doc.get(backward + 1, 5).equals("begin") ) { //$NON-NLS-1$ |
| command.text= command.text+command.text; |
| } |
| |
| smartIndentLine2(command, false, 1, null); |
| } |
| |
| private int searchParseStart(final int offset) throws BadLocationException, BadPartitioningException { |
| final AbstractDocument doc= getDocument(); |
| final ITypedRegion partition= doc.getPartition(getDocumentContentInfo().getPartitioning(), |
| offset, false ); |
| if (partition.getType() == TexDocumentConstants.LTX_DEFAULT_CONTENT_TYPE) { |
| return offset; |
| } |
| if (partition.getType() == TexDocumentConstants.LTX_MATH_CONTENT_TYPE |
| || partition.getType() == TexDocumentConstants.LTX_MATHCOMMENT_CONTENT_TYPE ) { |
| return LtxHeuristicTokenScanner.getSafeMathPartitionOffset( |
| doc.getDocumentPartitioner(getDocumentContentInfo().getPartitioning()), |
| offset ); |
| } |
| if (partition.getType() == TexDocumentConstants.LTX_COMMENT_CONTENT_TYPE |
| || partition.getType() == TexDocumentConstants.LTX_VERBATIM_CONTENT_TYPE ) { |
| return partition.getOffset() + partition.getLength(); |
| } |
| return -1; |
| } |
| |
| /** |
| * Generic method to indent lines using the |
| * @param command handle to read and save the document informations |
| * @param indentCurrentLine |
| * @param setCaret positive values indicates the line to set the caret |
| * @param traceCursor offset to update and return (offset at state after insertion of c.text) |
| */ |
| private Position[] smartIndentLine2(final DocumentCommand command, final boolean indentCurrentLine, |
| final int setCaret, final Position[] tracePos) throws BadLocationException, BadPartitioningException, CoreException { |
| if (getEditor3() == null) { |
| return tracePos; |
| } |
| final AbstractDocument doc= getDocument(); |
| final TextRegion validRegion= getValidRange(); |
| |
| // new algorithm using RSourceIndenter |
| final int cEnd= command.offset+command.length; |
| if (cEnd > validRegion.getEndOffset()) { |
| return tracePos; |
| } |
| this.scanner.configure(doc); |
| final int smartEnd; |
| final String smartAppend; |
| if (endsWithNewLine(command.text)) { |
| final IRegion cEndLine= doc.getLineInformationOfOffset(cEnd); |
| final int validEnd= (cEndLine.getOffset() + cEndLine.getLength() <= validRegion.getEndOffset()) ? |
| cEndLine.getOffset() + cEndLine.getLength() : |
| validRegion.getEndOffset(); |
| final int next= this.scanner.findAnyNonBlankForward(cEnd, validEnd, false); |
| smartEnd= (next >= 0) ? next : validEnd; |
| smartAppend= ""; //$NON-NLS-1$ |
| } |
| else { |
| smartEnd= cEnd; |
| smartAppend= ""; //$NON-NLS-1$ |
| } |
| |
| int shift= 0; |
| if (command.offset < validRegion.getStartOffset() |
| || command.offset > validRegion.getEndOffset()) { |
| return tracePos; |
| } |
| if (command.offset > 2500) { |
| final int line= doc.getLineOfOffset(command.offset) - 40; |
| if (line >= 10) { |
| final int lineOffset= doc.getLineOffset(line); |
| shift= searchParseStart(lineOffset); |
| } |
| } |
| if (shift < validRegion.getStartOffset()) { |
| shift= validRegion.getStartOffset(); |
| } |
| int dummyDocEnd= cEnd+1500; |
| if (dummyDocEnd > validRegion.getEndOffset()) { |
| dummyDocEnd= validRegion.getEndOffset(); |
| } |
| final String text; |
| { final StringBuilder s= new StringBuilder( |
| (command.offset-shift) + |
| command.text.length() + |
| (smartEnd-cEnd) + |
| smartAppend.length() + |
| (dummyDocEnd-smartEnd) ); |
| s.append(doc.get(shift, command.offset-shift)); |
| s.append(command.text); |
| if (smartEnd-cEnd > 0) { |
| s.append(doc.get(cEnd, smartEnd-cEnd)); |
| } |
| s.append(smartAppend); |
| s.append(doc.get(smartEnd, dummyDocEnd-smartEnd)); |
| text= s.toString(); |
| } |
| |
| // Create temp doc to compute indent |
| int dummyCoffset= command.offset-shift; |
| int dummyCend= dummyCoffset+command.text.length(); |
| final AbstractDocument dummyDoc= new Document(text); |
| final TextParserInput parserInput= (Display.getCurrent() == Display.getDefault()) ? |
| DEFAULT_PARSER_INPUT.reset(text) : new StringParserInput(text); |
| |
| // Lines to indent |
| int dummyFirstLine= dummyDoc.getLineOfOffset(dummyCoffset); |
| final int dummyLastLine= dummyDoc.getLineOfOffset(dummyCend); |
| if (!indentCurrentLine) { |
| dummyFirstLine++; |
| } |
| if (dummyFirstLine > dummyLastLine) { |
| return tracePos; |
| } |
| |
| // Compute indent |
| final LtxParser scanner= new LtxParser(new NowebLtxLexer(), null); |
| final SourceComponent rootNode= scanner.parse(parserInput.init(), |
| this.texCoreAccess.getTexCommandSet() ); |
| if (this.indenter == null) { |
| this.indenter= new LtxSourceIndenter(); |
| } |
| this.indenter.setup(this.texCoreAccess); |
| final TextEdit edit= this.indenter.getIndentEdits(dummyDoc, rootNode, 0, dummyFirstLine, dummyLastLine); |
| |
| // Apply indent to temp doc |
| final Position cPos= new Position(dummyCoffset, command.text.length()); |
| dummyDoc.addPosition(cPos); |
| if (tracePos != null) { |
| for (int i= 0; i < tracePos.length; i++) { |
| tracePos[i].offset-= shift; |
| dummyDoc.addPosition(tracePos[i]); |
| } |
| } |
| |
| command.length= command.length+edit.getLength() |
| // add space between two replacement regions |
| // minus overlaps with c.text |
| -TextUtil.overlaps(edit.getOffset(), edit.getExclusiveEnd(), dummyCoffset, dummyCend); |
| if (edit.getOffset() < dummyCoffset) { // move offset, if edit begins before c |
| dummyCoffset= edit.getOffset(); |
| command.offset= shift+dummyCoffset; |
| } |
| edit.apply(dummyDoc, TextEdit.NONE); |
| |
| // Read indent for real doc |
| int dummyChangeEnd= edit.getExclusiveEnd(); |
| dummyCend= cPos.getOffset()+cPos.getLength(); |
| if (!cPos.isDeleted && dummyCend > dummyChangeEnd) { |
| dummyChangeEnd= dummyCend; |
| } |
| command.text= dummyDoc.get(dummyCoffset, dummyChangeEnd-dummyCoffset); |
| if (setCaret != 0) { |
| command.caretOffset= shift+this.indenter.getNewIndentOffset(dummyFirstLine+setCaret-1); |
| command.shiftsCaret= false; |
| } |
| this.indenter.clear(); |
| if (tracePos != null) { |
| for (int i= 0; i < tracePos.length; i++) { |
| tracePos[i].offset+= shift; |
| } |
| } |
| return tracePos; |
| } |
| |
| protected void smartLineWrap(final DocumentCommand command) |
| throws BadLocationException, BadPartitioningException, CoreException { |
| if (command.length != 0) { |
| return; |
| } |
| this.hardLineWrap.doWrapB(getDocument(), command, this.texCodeStyle.getLineWidth()); |
| } |
| |
| private LinkedModeUI createLinkedMode(final int offset, final char type, final int mode) |
| throws BadLocationException { |
| final LinkedModeModel model= new LinkedModeModel(); |
| int pos= 0; |
| |
| final LinkedPositionGroup group= new LinkedPositionGroup(); |
| final LinkedPosition position= TexBracketLevel.createPosition(type, getDocument(), |
| offset + 1, 0, pos++ ); |
| group.addPosition(position); |
| model.addGroup(group); |
| |
| model.forceInstall(); |
| |
| final TexBracketLevel level= new TexBracketLevel(model, |
| getDocument(), getDocumentContentInfo(), |
| ImCollections.newList(position), (mode & 0xffff0000) ); |
| |
| /* create UI */ |
| final LinkedModeUI ui= new LinkedModeUI(model, getViewer()); |
| ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER); |
| ui.setExitPosition(getViewer(), offset + (mode & 0xff), 0, pos); |
| ui.setSimpleMode(true); |
| ui.setExitPolicy(level); |
| return ui; |
| } |
| |
| } |