/******************************************************************************* * Copyright (c) 2005, 2017 IBM Corporation 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 * *******************************************************************************/ package org.eclipse.dltk.tcl.internal.ui.text; import java.util.ArrayList; import java.util.List; import org.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.tcl.internal.ui.TclUI; import org.eclipse.dltk.tcl.ui.TclPreferenceConstants; import org.eclipse.dltk.tcl.ui.text.TclPartitions; import org.eclipse.dltk.ui.CodeFormatterConstants; import org.eclipse.dltk.ui.PreferenceConstants; import org.eclipse.dltk.ui.text.util.AutoEditUtils; import org.eclipse.dltk.utils.CharacterStack; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.rules.FastPartitioner; /** * Auto indent strategy sensitive to brackets. */ public class TclAutoEditStrategy extends DefaultIndentLineAutoEditStrategy { private final IPreferenceStore preferenceStore; private final String fPartitioning; private boolean closeStrings() { return preferenceStore .getBoolean(PreferenceConstants.EDITOR_CLOSE_STRINGS); } private boolean closeBrackets() { return preferenceStore .getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACKETS); } private boolean closeBraces() { return preferenceStore .getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACES); } /* * Switch smart mode on/off */ private boolean isSmartMode() { return preferenceStore .getBoolean(PreferenceConstants.EDITOR_SMART_INDENT); } /** * Calculates real length of string. So any char except \t has length 1, \t * has length getTabWidth. * * @param str * string to process * @return length */ public int getPhysicalLength(String str) { int res = 0; for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == '\t') res += getTabSize(); else res++; } return res; } private int getTabSize() { return preferenceStore .getInt(CodeFormatterConstants.FORMATTER_TAB_SIZE); } private int getIndentSize() { return preferenceStore .getInt(CodeFormatterConstants.FORMATTER_INDENTATION_SIZE); } private String getTabStyle() { return preferenceStore .getString(CodeFormatterConstants.FORMATTER_TAB_CHAR); } private boolean isSmartPasteMode1() { return preferenceStore.getInt( TclPreferenceConstants.EDITOR_SMART_PASTE_MODE) == TclPreferenceConstants.EDITOR_SMART_PASTE_MODE_SIMPLE; } private boolean isSmartPasteMode2() { return preferenceStore.getInt( TclPreferenceConstants.EDITOR_SMART_PASTE_MODE) == TclPreferenceConstants.EDITOR_SMART_PASTE_MODE_FULL; } public TclAutoEditStrategy(IPreferenceStore store, String part) { preferenceStore = store; fPartitioning = part; } private boolean isLineDelimiter(IDocument document, String text) { String[] delimiters = document.getLegalLineDelimiters(); if (delimiters != null) return TextUtilities.equals(delimiters, text) > -1; return false; } /** * Returns the leading whitespaces. * * @param document * - the document being parsed * @param line * - the line being searched * @return the leading whitespace * @throws BadLocationException * in case <code>line</code> is invalid in the document */ private String getLineIndent(IDocument document, int line) throws BadLocationException { if (line > -1) { int start = document.getLineOffset(line); int end = start + document.getLineLength(line); int whiteend = findEndOfWhiteSpace(document, start, end); return document.get(start, whiteend - start); } return ""; //$NON-NLS-1$ } /** * Returns the leading whitespaces and tabs. * * @param line * - the line being searched * @return the leading whitespace */ public String getLineIndent(String line) { int end = line.length(); int whiteend = end; int offset = 0; while (offset < end) { char c = line.charAt(offset); if (c != ' ' && c != '\t') { whiteend = offset; break; } offset++; } return line.substring(0, whiteend); } /* * Block is and opening char seq. and closing char seq. Each block have it's * own indent */ private static abstract class TclBlock { private int offset; public char openingPeer; public char closingPeer; public String indent; protected TclBlock(int o) { offset = o; } public int getOffset() { return offset; } } private class RoundBracketBlock extends TclBlock { public RoundBracketBlock(int offset) { super(offset); openingPeer = '('; closingPeer = ')'; if (!getTabStyle().equals(CodeFormatterConstants.TAB)) indent = " "; else indent = "\t"; } } private class BracketBlock extends TclBlock { public BracketBlock(int offset) { super(offset); openingPeer = '['; closingPeer = ']'; if (!getTabStyle().equals(CodeFormatterConstants.TAB)) indent = " "; else indent = "\t"; } } private class BraceBlock extends TclBlock { public BraceBlock(int offset) { super(offset); openingPeer = '{'; closingPeer = '}'; if (!getTabStyle().equals(CodeFormatterConstants.SPACE)) indent = "\t"; else { indent = AutoEditUtils.getNSpaces(getIndentSize()); } } } /** * Return pair to brace. Ex. '(' for ')', e.t.c. * * @param b * input brace * @return peer brace */ private char getBracePair(char b) { switch (b) { case '(': return ')'; case ')': return '('; case '[': return ']'; case ']': return '['; case '{': return '}'; case '}': return '{'; case '\"': return '\"'; case '\'': return '\''; } return b; } private static final int MAX_BACK_SCAN_SIZE = 16384; /** * Determines type of last opening block. For example, for such line <code> * proc () { * </code> function will return new BraceBlockType. And for * <code>proc(){}</code> function will return null * * @param d * document containing the line * @param line * number of the start search offset * @return an object of appropriate block type * @throws BadLocationException */ private TclBlock getLastOpenBlockType(IDocument d, int start) throws BadLocationException { // IRegion lineReg = d.getLineInformation(line); final CharacterStack blocks = new CharacterStack(); // String lineStr = d.get(lineReg.getOffset(), lineReg.getLength()); ITypedRegion lastRegion = null; int lastLine = -1; int lastLineOffset = -1; String lastLineStr = Util.EMPTY_STRING; final int stopPosition = Math.max(start - MAX_BACK_SCAN_SIZE, 0); int offset = start; while (offset > stopPosition) { offset--; // skip screening int bslashes = 0; while (offset - bslashes > 0 && d.getChar(offset - bslashes - 1) == '\\') bslashes++; if (bslashes % 2 == 1) { offset -= bslashes; continue; } // skip comment lines if (lastLineOffset < 0 || offset < lastLineOffset) { lastLine = d.getLineOfOffset(offset); lastLineOffset = d.getLineOffset(lastLine); lastLineStr = d.get(lastLineOffset, d.getLineLength(lastLine)) .trim(); } if (lastLineStr.length() != 0 && lastLineStr.charAt(0) == '#') { offset = lastLineOffset; continue; } // skip strings if (lastRegion == null || offset < lastRegion.getOffset()) { lastRegion = TextUtilities.getPartition(d, fPartitioning, offset, true); } if (lastRegion.getType() == TclPartitions.TCL_STRING) { offset = lastRegion.getOffset(); offset--; } char c = d.getChar(offset); boolean insideFig = false; if (blocks.size() > 0 && blocks.peek() == '}') insideFig = true; // ommit everything inside {} if (c != '{' && c != '}' && insideFig) continue; switch (c) { case '(': if (0 == blocks.size()) return new RoundBracketBlock(offset); if (blocks.pop() != ')') return new RoundBracketBlock(offset); break; case '[': if (0 == blocks.size()) return new BracketBlock(offset); if (blocks.pop() != ']') return new BracketBlock(offset); break; case '{': if (0 == blocks.size()) return new BraceBlock(offset); if (blocks.pop() != '}') return new BraceBlock(offset); break; case ')': case ']': case '}': blocks.push(c); break; } } return null; } /** * Find line with number <=line, that is Tcl code line (not comment) * * @param d * the document to search in * @param line * number of starting line * @return number of code line or -1 if no such line found */ private int getLastCodeLine(IDocument d, int line) { int res = line; try { while (res > -1) { IRegion reg = d.getLineInformation(res); String str = d.get(reg.getOffset(), reg.getLength()).trim(); if (!str.startsWith("#") && str.length() > 0) return res; res--; } } catch (BadLocationException e) { e.printStackTrace(); } return res; } private String getDocumentLine(IDocument d, int line) throws BadLocationException { int start = d.getLineOffset(line); int length = d.getLineLength(line); return d.get(start, length); } private void smartIndentAfterNewLine(IDocument d, DocumentCommand c) { if (c.offset == -1 || d.getLength() == 0) return; try { TclDocumentScanner scanner = new TclDocumentScanner(d, fPartitioning, IDocument.DEFAULT_CONTENT_TYPE); int pos = (c.offset == d.getLength() ? c.offset - 1 : c.offset); int line = d.getLineOfOffset(pos); int curLine = d.getLineOfOffset(c.offset); String curLineStr = getDocumentLine(d, curLine); String resultIndent = ""; String lastIndent = ""; TclBlock block = null; boolean needPeer = false; // if we need to jump into middle of block without inserting peer // brace boolean dummyPeer = false; block = getLastOpenBlockType(d, c.offset); if (curLineStr.trim().endsWith("\\")) { resultIndent = getLineIndent(d, line - 1); } else if (block == null) { int lastCodeLine = getLastCodeLine(d, line); // no code above us, just copy last indent if (-1 == lastCodeLine) { resultIndent = getLineIndent(d, line - 1); } else { // if our line is inside brackets, get line with opening // bracket block = getLastOpenBlockType(d, d.getLineOffset(lastCodeLine)); if (block != null) { int peer = scanner.findOpeningPeer( d.getLineOffset(lastCodeLine), block.openingPeer, block.closingPeer); if (peer != TclDocumentScanner.NOT_FOUND) { lastCodeLine = d.getLineOfOffset(peer); } } resultIndent = getLineIndent(d, lastCodeLine); } } else { int lastCodeLine = d.getLineOfOffset(block.getOffset()); lastIndent = getLineIndent(d, lastCodeLine); resultIndent = lastIndent + block.indent; int cPos = pos; while ((d.getChar(cPos) == ' ' || d.getChar(cPos) == '\t')) { if (cPos == d.getLength() - 1) break; cPos++; } if (block.closingPeer == d.getChar(cPos)) { dummyPeer = true; } // find closing peer, if exists int peerOffset = scanner.findClosingPeer(pos, block.openingPeer, block.closingPeer); // if not fount peer, we need it if (peerOffset == TclDocumentScanner.NOT_FOUND) needPeer = true; } // process line indent resultIndent = remakeIndent(resultIndent); IRegion reg = d.getLineInformation(line); int lineEnd = reg.getOffset() + reg.getLength(); int contentStart = findEndOfWhiteSpace(d, c.offset, lineEnd); c.length = Math.max(contentStart - c.offset, 0); if (block instanceof BraceBlock && !preferenceStore .getBoolean(PreferenceConstants.EDITOR_CLOSE_BRACES)) needPeer = false; if ((block instanceof BracketBlock || block instanceof RoundBracketBlock) && !preferenceStore.getBoolean( PreferenceConstants.EDITOR_CLOSE_BRACKETS)) needPeer = false; if (needPeer || dummyPeer) { StringBuffer buf = new StringBuffer(c.text); buf.append(resultIndent); c.shiftsCaret = false; c.caretOffset = c.offset + buf.length(); if (lineEnd - contentStart > 0 && !dummyPeer) { c.length = lineEnd - c.offset; buf.append(d.get(contentStart, lineEnd - contentStart) .toCharArray()); } buf.append("\n"); // may be we should we default line delimeter? buf.append(lastIndent); if (!dummyPeer) buf.append(block.closingPeer); c.text = buf.toString(); } else { StringBuffer buf = new StringBuffer(c.text); buf.append(resultIndent); c.text = buf.toString(); } } catch (BadLocationException e) { e.printStackTrace(); } } private void smartIndentAfterOpeningBracket(IDocument d, DocumentCommand c) { if (c.offset == -1) return; try { if (d.getChar(c.offset - 1) == '\\') return; } catch (BadLocationException e1) { } if ('\"' == c.text.charAt(0) && !closeStrings()) return; if ('\'' == c.text.charAt(0) && !closeStrings()) return; if (!closeBrackets() && ('[' == c.text.charAt(0) || '(' == c.text.charAt(0))) return; if (!closeBraces() && ('{' == c.text.charAt(0))) return; try { char ch = c.text.charAt(0); switch (ch) { case '\"': case '\'': // if we close existing quote, do nothing if ('\"' == ch && c.offset > 0 && "\"".equals(d.get(c.offset - 1, 1))) return; if ('\'' == ch && c.offset > 0 && "\'".equals(d.get(c.offset - 1, 1))) return; if (c.offset != d.getLength() && ch == d.get(c.offset, 1).charAt(0)) c.text = ""; else { c.text += c.text; c.length = 0; } c.shiftsCaret = false; c.caretOffset = c.offset + 1; break; case '(': case '{': case '[': boolean needPeer = false; TclDocumentScanner scanner = new TclDocumentScanner(d, fPartitioning, IDocument.DEFAULT_CONTENT_TYPE); // find closing peer, if exists int peerOffset = scanner.findClosingPeer(c.offset, ch, getBracePair(ch)); // if not fount peer, we need it if (peerOffset == TclDocumentScanner.NOT_FOUND) needPeer = true; // check partition if (getRegionType(d, c.offset) != IDocument.DEFAULT_CONTENT_TYPE) return; if (!needPeer) return; if (c.offset != d.getLength() && ch == d.get(c.offset, 1).charAt(0)) return; // add closing peer c.text = c.text + getBracePair(ch); c.length = 0; c.shiftsCaret = false; c.caretOffset = c.offset + 1; break; } } catch (BadLocationException e) { e.printStackTrace(); } } private void smartIndentAfterClosingBracket(IDocument d, DocumentCommand c) { if (c.offset == -1 || d.getLength() == 0) return; try { char bracket = c.text.charAt(0); // if we already have bracket we should jump over it if (c.offset != d.getLength() && bracket == d.get(c.offset, 1).charAt(0) && (getRegionType(d, c.offset) == IDocument.DEFAULT_CONTENT_TYPE)) { if ((bracket == '}' && closeBraces()) || ((bracket == ')' || bracket == ']') && closeBrackets())) { c.text = ""; c.shiftsCaret = false; c.caretOffset = c.offset + 1; return; } } TclDocumentScanner scanner = new TclDocumentScanner(d); int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset); int line = d.getLineOfOffset(p); int start = d.getLineOffset(line); int whiteend = findEndOfWhiteSpace(d, start, c.offset); // shift only when line does not contain any text up to the closing // bracket if (whiteend == c.offset) { // determine block type TclBlock block = null; switch (c.text.charAt(0)) { case ']': block = new BracketBlock(0); break; case '}': block = new BraceBlock(0); break; case ')': block = new RoundBracketBlock(0); break; } if (block == null) return; // evaluate the line with the opening bracket that matches out // closing bracket int reference = scanner.findOpeningPeer(p, block.openingPeer, block.closingPeer); int indLine = d.getLineOfOffset(reference); if (indLine != -1 && indLine != line) { // take the indent of the found line StringBuffer replaceText = new StringBuffer(); // add the rest of the current line including the just added // close bracket replaceText.append(getLineIndent(d, indLine)); replaceText.append(c.text); // modify document command c.length += c.offset - start; c.offset = start; c.text = replaceText.toString(); } } } catch (BadLocationException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } private boolean smartIndentJump(IDocument d, DocumentCommand c) { if (c.offset == -1 || d.getLength() == 0) return false; try { TclDocumentScanner scanner = new TclDocumentScanner(d, fPartitioning, IDocument.DEFAULT_CONTENT_TYPE); int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset); int curLine = d.getLineOfOffset(c.offset); String curLineStr = getDocumentLine(d, curLine); int line = d.getLineOfOffset(p); int start = d.getLineOffset(line); String resultIndent = ""; String lastIndent = ""; TclBlock block; // DUPLICATION: this code is identical to code in // smartInsertAfterNewLine block = getLastOpenBlockType(d, c.offset); if (curLineStr.trim().endsWith("\\")) { resultIndent = getLineIndent(d, line - 1); } else if (block == null) { int lastCodeLine = getLastCodeLine(d, line); // if our line is inside brackets, get line with opening bracket block = getLastOpenBlockType(d, d.getLineOffset(curLine)); if (block != null) { int peer = scanner.findOpeningPeer(d.getLineOffset(curLine), block.openingPeer, block.closingPeer); if (peer != TclDocumentScanner.NOT_FOUND) { lastCodeLine = d.getLineOfOffset(peer); } } // no code above us, just copy last indent if (-1 == lastCodeLine) { resultIndent = getLineIndent(d, line - 1); } else { resultIndent = getLineIndent(d, lastCodeLine); } } else { int lastCodeLine = d.getLineOfOffset(block.getOffset()); lastIndent = getLineIndent(d, lastCodeLine); resultIndent = lastIndent + block.indent; } if (c.offset >= start + resultIndent.length()) return false; // we already in the place String currentIndent = getLineIndent(d, line); if (!currentIndent.startsWith(resultIndent)) return false; // we have no place to jump c.length = 0; c.shiftsCaret = false; c.text = ""; c.caretOffset = d.getLineOffset(line) + resultIndent.length(); } catch (BadLocationException e) { e.printStackTrace(); return false; } return true; } /** * Installs a partitioner with <code>document</code>. * * @param document * the document */ private static void installStuff(Document document) { String[] types = new String[] { TclPartitions.TCL_STRING, TclPartitions.TCL_COMMENT, IDocument.DEFAULT_CONTENT_TYPE }; FastPartitioner partitioner = new FastPartitioner( new TclPartitionScanner(), types); partitioner.connect(document); document.setDocumentPartitioner(TclPartitions.TCL_PARTITIONING, partitioner); } /** * Removes a partitioner with <code>document</code>. * * @param document * the document */ private static void removeStuff(Document document) { document.setDocumentPartitioner(TclPartitions.TCL_PARTITIONING, null); } /** * Reindents c.text when pasting(simply indents all to common level). * * @param d * @param c */ private void smartPasteSimple(IDocument d, DocumentCommand c) { try { String content = d.get(0, c.offset) + c.text; Document temp = new Document(content); int line = d.getLineOfOffset(c.offset); int start = d.getLineOffset(line); int relativeIndent = 0; int sline = line + 1; String commonIndent = getLineIndent(d, line); int back = -1; if (d.get(start, c.offset - start).trim().length() == 0) { // we are // inserting // lines // block // TODO: recalc common indent // try to detect cutten line int i; int depth = 0; myloop: for (i = 0; i < c.text.length(); i++) { switch (c.text.charAt(i)) { case '(': case '{': case '[': depth++; break; case ')': case ']': case '}': depth--; break; case '\n': break myloop; } } if (depth == 0 && i != c.text.length() && getRegionType(temp, c.offset + i) != TclPartitions.TCL_STRING) { String first = getLineIndent(c.text.substring(0, i)); String second = getLineIndent(temp, line + 1); temp.replace(start, c.offset - start + first.length(), second); } else temp.replace(start, c.offset - start, ""); back = c.offset - start; relativeIndent = getPhysicalLength(getLineIndent(temp, line)); sline = line; } while (true) { try { getDocumentLine(temp, sline); } catch (BadLocationException e) { break; // signal of the end of lines } String currentIndent = getLineIndent(temp, sline); int newIndentLen = getPhysicalLength(commonIndent) + getPhysicalLength(currentIndent) - relativeIndent; String newIndent = generateIndent(newIndentLen); // may be do // here temp.replace(temp.getLineOffset(sline), currentIndent.length(), newIndent); sline++; } if (back > 0) { c.offset = start; c.text = temp.get(start, temp.getLength() - start); c.length += back; } else { c.text = temp.get(c.offset, temp.getLength() - c.offset); } } catch (BadLocationException e) { e.printStackTrace(); } } private String generateIndent(int newIndentLen) { String res = ""; if (!getTabStyle().equals(CodeFormatterConstants.SPACE)) { int ts = getTabSize(); while (newIndentLen >= ts) { res += "\t"; newIndentLen -= ts; } } if (getTabStyle().equals(CodeFormatterConstants.TAB)) { if (newIndentLen > 0) res += "\t"; } else { for (int i = 0; i < newIndentLen; i++) res += " "; } return res; } private String remakeIndent(String indent) { int len = getPhysicalLength(indent); return generateIndent(len); } private void smartPaste2(IDocument d, DocumentCommand cmd) { try { String content = d.get(0, cmd.offset) + cmd.text; Document temp = new Document(content); installStuff(temp); List<TclBlock> blocks = new ArrayList<>(); int figs = 0; // count of braces int newOffset = cmd.offset; int cmdLine = d.getLineOfOffset(cmd.offset); int cmdLineStart = d.getLineOffset(cmdLine); int startLine = d.getLineOfOffset(cmd.offset) + 1; if (d.get(cmdLineStart, cmd.offset - cmdLineStart).trim() .length() == 0) { // we are inserting lines block startLine--; newOffset = cmdLineStart; } int offset = 0; while (offset < temp.getLength()) { ITypedRegion region = TextUtilities.getPartition(temp, fPartitioning, offset, true); if (region.getType() != IDocument.DEFAULT_CONTENT_TYPE && figs == 0) { offset = region.getOffset() + region.getLength(); continue; } char c = temp.getChar(offset); if (c == '\\') { offset += 2; continue; } switch (c) { case ')': case ']': case '}': if (c == '}') figs--; if (blocks.size() > 0) { blocks.remove(blocks.size() - 1); } break; } int line = temp.getLineOfOffset(offset); String currentIndent = getLineIndent(temp, line); // if may start reindenting if (line >= startLine && offset == temp.getLineOffset(line) + currentIndent.length()) { StringBuffer newIndentBuf = new StringBuffer(); for (TclBlock b : blocks) { newIndentBuf.append(b.indent); } String newIndent = newIndentBuf.toString(); temp.replace(temp.getLineOffset(line), currentIndent.length(), newIndent); offset = temp.getLineOffset(line) + newIndent.length(); } switch (c) { case '(': blocks.add(new RoundBracketBlock(offset)); break; case '[': blocks.add(new BracketBlock(offset)); break; case '{': figs++; blocks.add(new BraceBlock(offset)); break; } offset++; } cmd.text = temp.get(newOffset, temp.getLength() - newOffset); cmd.offset = newOffset; removeStuff(temp); } catch (BadLocationException e) { TclUI.error("Error in TclAutoEditStrategy.smartPaste2", e); //$NON-NLS-1$ } } /** * get partition covering offset * * @param d * @param offset * @return * @throws BadLocationException */ private String getRegionType(IDocument d, int offset) throws BadLocationException { ITypedRegion region = TextUtilities.getPartition(d, fPartitioning, offset, true); return region.getType(); } /* * @see * org.eclipse.jface.text.IAutoIndentStrategy#customizeDocumentCommand(org * .eclipse.jface.text.IDocument, org.eclipse.jface.text.DocumentCommand) */ @Override public void customizeDocumentCommand(IDocument d, DocumentCommand c) { if (c.doit == false) return; if (c.length == 0 && c.text != null && isLineDelimiter(d, c.text)) { if (isSmartMode()) smartIndentAfterNewLine(d, c); else { super.customizeDocumentCommand(d, c); return; } } else if (c.length <= 1 && c.text.length() == 1) { switch (c.text.charAt(0)) { case '}': case ']': case ')': smartIndentAfterClosingBracket(d, c); break; // case '\"': // double quote is handled in TclBracketInserter case '(': case '{': case '[': smartIndentAfterOpeningBracket(d, c); break; case '\t': boolean jumped = false; if (preferenceStore .getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) { jumped = smartIndentJump(d, c); } if (!jumped) { // process tab key using format options if (getTabStyle().equals(CodeFormatterConstants.SPACE)) { c.text = ""; int ts = getTabSize(); for (int i = 0; i < ts; i++) { c.text += " "; } } } break; } } else if (c.text.length() >= 1 && isSmartPasteMode1()) { smartPasteSimple(d, c); // } else if (c.text.length() >= 1 && isSmartPasteMode2()) { smartPaste2(d, c); } } }