| Author | DaveJarvis <email> |
|---|---|
| Date | 2020-06-15 20:54:40 GMT-0700 |
| Commit | 31e5d939472257d9826b33855c757f4b12aa8efd |
| Parent | 64223e0 |
| Delta | 19 lines added, 484 lines removed, 465-line decrease |
| -/* | ||
| - * Copyright 2020 White Magic Software, Ltd. | ||
| - * | ||
| - * All rights reserved. | ||
| - * | ||
| - * Redistribution and use in source and binary forms, with or without | ||
| - * modification, are permitted provided that the following conditions are met: | ||
| - * | ||
| - * o Redistributions of source code must retain the above copyright | ||
| - * notice, this list of conditions and the following disclaimer. | ||
| - * | ||
| - * o Redistributions in binary form must reproduce the above copyright | ||
| - * notice, this list of conditions and the following disclaimer in the | ||
| - * documentation and/or other materials provided with the distribution. | ||
| - * | ||
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| - */ | ||
| -package com.scrivenvar.processors.markdown; | ||
| - | ||
| -import static java.lang.Character.isLetter; | ||
| -import static java.lang.Math.min; | ||
| - | ||
| -import com.scrivenvar.processors.CaretInsertionProcessor; | ||
| -import com.scrivenvar.processors.Processor; | ||
| -import javafx.beans.value.ObservableValue; | ||
| - | ||
| -/** | ||
| - * Responsible for inserting a caret position token into a markdown document. | ||
| - * | ||
| - * @author White Magic Software, Ltd. | ||
| - */ | ||
| -public class MarkdownCaretInsertionProcessor extends CaretInsertionProcessor { | ||
| - | ||
| - /** | ||
| - * Constructs a processor capable of inserting a caret marker into Markdown. | ||
| - * | ||
| - * @param processor The next processor in the chain. | ||
| - * @param position The caret's current position in the text. | ||
| - */ | ||
| - public MarkdownCaretInsertionProcessor( | ||
| - final Processor<String> processor, | ||
| - final ObservableValue<Integer> position ) { | ||
| - super( processor, position ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Changes the text to insert a "caret" at the caret position. This will | ||
| - * insert the unique key of Constants.MD_CARET_POSITION into the document. | ||
| - * | ||
| - * @param t The text document to process. | ||
| - * @return The text with the caret position token inserted at the caret | ||
| - * position. | ||
| - */ | ||
| - @Override | ||
| - public String processLink( final String t ) { | ||
| - final int length = t.length(); | ||
| - int offset = min( getCaretPosition(), length ); | ||
| - | ||
| - // TODO: Ensure that the caret position is outside of an element, | ||
| - // so that a caret inserted in the image doesn't corrupt it. Such as: | ||
| - // | ||
| - //  | ||
| - // | ||
| - // 1. Scan back to the previous EOL, which will be the MD AST start point. | ||
| - // 2. Scan forward until EOF or EOL, which will be the MD AST ending point. | ||
| - // 3. Convert the text between start and end into MD AST. | ||
| - // 4. Find the nearest text node to the caret. | ||
| - // 5. Insert the CARET_POSITION_MD value in the text at that offsset. | ||
| - // Insert the caret at the closest non-Markdown delimiter (i.e., the | ||
| - // closest character from the caret position forward). | ||
| - while( offset < length && !isLetter( t.charAt( offset ) ) ) { | ||
| - offset++; | ||
| - } | ||
| - | ||
| - return inject( t, offset ); | ||
| - } | ||
| -} | ||
| -/* | ||
| - * Copyright 2016 White Magic Software, Ltd. | ||
| - * | ||
| - * All rights reserved. | ||
| - * | ||
| - * Redistribution and use in source and binary forms, with or without | ||
| - * modification, are permitted provided that the following conditions are met: | ||
| - * | ||
| - * o Redistributions of source code must retain the above copyright | ||
| - * notice, this list of conditions and the following disclaimer. | ||
| - * | ||
| - * o Redistributions in binary form must reproduce the above copyright | ||
| - * notice, this list of conditions and the following disclaimer in the | ||
| - * documentation and/or other materials provided with the distribution. | ||
| - * | ||
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| - */ | ||
| -package com.scrivenvar.processors; | ||
| - | ||
| -import static com.scrivenvar.Constants.CARET_POSITION_HTML; | ||
| -import static com.scrivenvar.Constants.CARET_POSITION_MD; | ||
| - | ||
| -/** | ||
| - * Responsible for replacing the caret position marker with an HTML element | ||
| - * suitable to use as a reference for scrolling a view port. | ||
| - * | ||
| - * @author White Magic Software, Ltd. | ||
| - */ | ||
| -public class CaretReplacementProcessor extends AbstractProcessor<String> { | ||
| - | ||
| - public CaretReplacementProcessor( final Processor<String> processor ) { | ||
| - super( processor ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Replaces each MD_CARET_POSITION with an HTML element that has an id | ||
| - * attribute of CARET_POSITION. This should only replace one item. | ||
| - * | ||
| - * @param t The text that contains | ||
| - * @return The value of the first instance replaced. | ||
| - */ | ||
| - @Override | ||
| - public String processLink( final String t ) { | ||
| - return replace( t, CARET_POSITION_MD, CARET_POSITION_HTML ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Replaces the needle with thread in the given haystack. Based on Apache | ||
| - * Commons 3 StringUtils.replace method. Should be faster than String.replace, | ||
| - * which performs a little regex under the hood. | ||
| - * | ||
| - * @param haystack Search this string for the needle, must not be null. | ||
| - * @param needle The text to find in the haystack. | ||
| - * @param thread Replace the needle with this text, if the needle is found. | ||
| - * @return The haystack with the first instance of needle replaced with | ||
| - * thread. | ||
| - */ | ||
| - @SuppressWarnings("SameParameterValue") | ||
| - private static String replace( | ||
| - final String haystack, final String needle, final String thread ) { | ||
| - final int end = haystack.indexOf( needle ); | ||
| - | ||
| - return end == INDEX_NOT_FOUND ? | ||
| - haystack : | ||
| - haystack.substring( 0, end ) + thread + | ||
| - haystack.substring( end + needle.length() ); | ||
| - } | ||
| -} | ||
| import com.scrivenvar.FileEditorTab; | ||
| import com.scrivenvar.preview.HTMLPreviewPane; | ||
| -import com.scrivenvar.processors.markdown.MarkdownCaretInsertionProcessor; | ||
| import com.scrivenvar.processors.markdown.MarkdownProcessor; | ||
| -import javafx.beans.value.ObservableValue; | ||
| import java.nio.file.Path; | ||
| private final HTMLPreviewPane mPreviewPane; | ||
| private final Map<String, String> mResolvedMap; | ||
| - private final Processor<String> mCommonProcessor; | ||
| + private final Processor<String> mMarkdownProcessor; | ||
| /** | ||
| mPreviewPane = previewPane; | ||
| mResolvedMap = resolvedMap; | ||
| - mCommonProcessor = createCommonProcessor(); | ||
| + mMarkdownProcessor = createMarkdownProcessor(); | ||
| } | ||
| switch( lookup( path ) ) { | ||
| case RMARKDOWN: | ||
| - processor = createRProcessor( tab ); | ||
| + processor = createRProcessor(); | ||
| break; | ||
| case SOURCE: | ||
| - processor = createMarkdownProcessor( tab ); | ||
| + processor = createMarkdownDefinitionProcessor(); | ||
| break; | ||
| return processor; | ||
| + } | ||
| + | ||
| + private Processor<String> createHTMLPreviewProcessor() { | ||
| + return new HTMLPreviewProcessor( getPreviewPane() ); | ||
| } | ||
| /** | ||
| * Creates and links the processors at the end of the processing chain. | ||
| * | ||
| * @return A markdown, caret replacement, and preview pane processor chain. | ||
| */ | ||
| - private Processor<String> createCommonProcessor() { | ||
| - final var hpp = new HTMLPreviewProcessor( getPreviewPane() ); | ||
| - final var mcrp = new CaretReplacementProcessor( hpp ); | ||
| - | ||
| - return new MarkdownProcessor( mcrp ); | ||
| + private Processor<String> createMarkdownProcessor() { | ||
| + final var hpp = createHTMLPreviewProcessor(); | ||
| + return new MarkdownProcessor( hpp ); | ||
| } | ||
| protected Processor<String> createIdentityProcessor() { | ||
| - final var hpp = new HTMLPreviewProcessor( getPreviewPane() ); | ||
| - | ||
| + final var hpp = createHTMLPreviewProcessor(); | ||
| return new IdentityProcessor( hpp ); | ||
| } | ||
| protected Processor<String> createDefinitionProcessor( | ||
| final Processor<String> p ) { | ||
| return new DefinitionProcessor( p, getResolvedMap() ); | ||
| } | ||
| - protected Processor<String> createMarkdownProcessor( | ||
| - final FileEditorTab tab ) { | ||
| - final var caret = tab.caretPositionProperty(); | ||
| + protected Processor<String> createMarkdownDefinitionProcessor() { | ||
| final var tpc = getCommonProcessor(); | ||
| - final var cip = createMarkdownInsertionProcessor( tpc, caret ); | ||
| - | ||
| - return createDefinitionProcessor( cip ); | ||
| + return createDefinitionProcessor( tpc ); | ||
| } | ||
| protected Processor<String> createXMLProcessor( final FileEditorTab tab ) { | ||
| - final var caret = tab.caretPositionProperty(); | ||
| final var tpc = getCommonProcessor(); | ||
| final var xmlp = new XMLProcessor( tpc, tab.getPath() ); | ||
| - final var dp = createDefinitionProcessor( xmlp ); | ||
| - | ||
| - return createXMLInsertionProcessor( dp, caret ); | ||
| + return createDefinitionProcessor( xmlp ); | ||
| } | ||
| - protected Processor<String> createRProcessor( final FileEditorTab tab ) { | ||
| - final var caret = tab.caretPositionProperty(); | ||
| + protected Processor<String> createRProcessor() { | ||
| final var tpc = getCommonProcessor(); | ||
| final var rp = new InlineRProcessor( tpc, getResolvedMap() ); | ||
| - final var rvp = new RVariableProcessor( rp, getResolvedMap() ); | ||
| - | ||
| - return createRInsertionProcessor( rvp, caret ); | ||
| + return new RVariableProcessor( rp, getResolvedMap() ); | ||
| } | ||
| protected Processor<String> createRXMLProcessor( final FileEditorTab tab ) { | ||
| - final var caret = tab.caretPositionProperty(); | ||
| final var tpc = getCommonProcessor(); | ||
| final var xmlp = new XMLProcessor( tpc, tab.getPath() ); | ||
| final var rp = new InlineRProcessor( xmlp, getResolvedMap() ); | ||
| - final var rvp = new RVariableProcessor( rp, getResolvedMap() ); | ||
| - | ||
| - return createXMLInsertionProcessor( rvp, caret ); | ||
| - } | ||
| - | ||
| - private Processor<String> createMarkdownInsertionProcessor( | ||
| - final Processor<String> tpc, final ObservableValue<Integer> caret ) { | ||
| - return new MarkdownCaretInsertionProcessor( tpc, caret ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Create an insertion processor that is aware of R statements and will insert | ||
| - * a caret outside of any statement the caret falls within. | ||
| - * | ||
| - * @param processor Another link in the processor chain. | ||
| - * @param caret The caret insertion point. | ||
| - * @return A processor that can insert a caret token without disturbing any R | ||
| - * code. | ||
| - */ | ||
| - private Processor<String> createRInsertionProcessor( | ||
| - final Processor<String> processor, | ||
| - final ObservableValue<Integer> caret ) { | ||
| - return new RMarkdownCaretInsertionProcessor( processor, caret ); | ||
| - } | ||
| - | ||
| - private Processor<String> createXMLInsertionProcessor( | ||
| - final Processor<String> tpc, final ObservableValue<Integer> caret ) { | ||
| - return new XMLCaretInsertionProcessor( tpc, caret ); | ||
| + return new RVariableProcessor( rp, getResolvedMap() ); | ||
| } | ||
| */ | ||
| private Processor<String> getCommonProcessor() { | ||
| - return mCommonProcessor; | ||
| + return mMarkdownProcessor; | ||
| } | ||
| } | ||
| -/* | ||
| - * Copyright 2016 White Magic Software, Ltd. | ||
| - * | ||
| - * All rights reserved. | ||
| - * | ||
| - * Redistribution and use in source and binary forms, with or without | ||
| - * modification, are permitted provided that the following conditions are met: | ||
| - * | ||
| - * o Redistributions of source code must retain the above copyright | ||
| - * notice, this list of conditions and the following disclaimer. | ||
| - * | ||
| - * o Redistributions in binary form must reproduce the above copyright | ||
| - * notice, this list of conditions and the following disclaimer in the | ||
| - * documentation and/or other materials provided with the distribution. | ||
| - * | ||
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| - */ | ||
| -package com.scrivenvar.processors; | ||
| - | ||
| -import static com.scrivenvar.decorators.RVariableDecorator.PREFIX; | ||
| -import static com.scrivenvar.decorators.RVariableDecorator.SUFFIX; | ||
| -import static java.lang.Integer.max; | ||
| - | ||
| -import com.scrivenvar.processors.markdown.MarkdownCaretInsertionProcessor; | ||
| -import javafx.beans.value.ObservableValue; | ||
| - | ||
| -/** | ||
| - * Responsible for inserting a caret position token into an R document. | ||
| - * | ||
| - * @author White Magic Software, Ltd. | ||
| - */ | ||
| -public class RMarkdownCaretInsertionProcessor | ||
| - extends MarkdownCaretInsertionProcessor { | ||
| - | ||
| - /** | ||
| - * Constructs a processor capable of inserting a caret marker into Markdown. | ||
| - * | ||
| - * @param processor The next processor in the chain. | ||
| - * @param position The caret's current position in the text. | ||
| - */ | ||
| - public RMarkdownCaretInsertionProcessor( | ||
| - final Processor<String> processor, | ||
| - final ObservableValue<Integer> position ) { | ||
| - super( processor, position ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Changes the text to insert a "caret" at the caret position. This will | ||
| - * insert the unique key of Constants.MD_CARET_POSITION into the document. | ||
| - * | ||
| - * @param text The text document to process. | ||
| - * @return The text with the caret position token inserted at the caret | ||
| - * position. | ||
| - */ | ||
| - @Override | ||
| - public String processLink( final String text ) { | ||
| - int offset = getCaretPosition(); | ||
| - | ||
| - // Search for inline R code from the start of the caret's paragraph. | ||
| - // This should be much faster than scanning text from the beginning. | ||
| - int index = text.lastIndexOf( NEWLINE, offset ); | ||
| - | ||
| - if( index == INDEX_NOT_FOUND ) { | ||
| - index = 0; | ||
| - } | ||
| - | ||
| - // Scan for an inline R statement, either from the nearest paragraph or | ||
| - // the beginning of the file, whichever was found first. | ||
| - index = text.indexOf( PREFIX, index ); | ||
| - | ||
| - // If there was no R prefix then insert at the caret's initial offset... | ||
| - if( index != INDEX_NOT_FOUND ) { | ||
| - // Otherwise, retain the starting index of the first R statement in the | ||
| - // paragraph. | ||
| - int rPrefix = index + 1; | ||
| - | ||
| - // Scan for inline R prefixes until the text is exhausted or indexed | ||
| - // beyond the caret position. | ||
| - while( index != INDEX_NOT_FOUND && index < offset ) { | ||
| - // Set rPrefix to the index that might precede the caret. The + 1 is | ||
| - // to skip passed the leading backtick in the prefix (`r#). | ||
| - rPrefix = index + 1; | ||
| - | ||
| - // If there are no more R prefixes, exit the loop and look for a | ||
| - // suffix starting from the rPrefix position. | ||
| - index = text.indexOf( PREFIX, rPrefix ); | ||
| - } | ||
| - | ||
| - // Scan from the character after the R prefix up to any R suffix. | ||
| - final int rSuffix = max( text.indexOf( SUFFIX, rPrefix ), rPrefix ); | ||
| - | ||
| - // If the caret falls between the rPrefix and rSuffix, then change the | ||
| - // insertion point. | ||
| - final boolean between = isBetween( offset, rPrefix, rSuffix ); | ||
| - | ||
| - // Insert the caret marker at the start of the R statement. | ||
| - if( between ) { | ||
| - offset = rPrefix - 1; | ||
| - } | ||
| - } | ||
| - | ||
| - return inject( text, offset ); | ||
| - } | ||
| -} | ||
| -/* | ||
| - * Copyright 2016 White Magic Software, Ltd. | ||
| - * | ||
| - * All rights reserved. | ||
| - * | ||
| - * Redistribution and use in source and binary forms, with or without | ||
| - * modification, are permitted provided that the following conditions are met: | ||
| - * | ||
| - * o Redistributions of source code must retain the above copyright | ||
| - * notice, this list of conditions and the following disclaimer. | ||
| - * | ||
| - * o Redistributions in binary form must reproduce the above copyright | ||
| - * notice, this list of conditions and the following disclaimer in the | ||
| - * documentation and/or other materials provided with the distribution. | ||
| - * | ||
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| - */ | ||
| -package com.scrivenvar.processors; | ||
| - | ||
| -import com.ximpleware.VTDException; | ||
| -import com.ximpleware.VTDGen; | ||
| -import static com.ximpleware.VTDGen.TOKEN_CHARACTER_DATA; | ||
| -import com.ximpleware.VTDNav; | ||
| -import static java.nio.charset.StandardCharsets.UTF_8; | ||
| -import java.text.ParseException; | ||
| -import javafx.beans.value.ObservableValue; | ||
| - | ||
| -/** | ||
| - * Inserts a caret position indicator into the document. | ||
| - * | ||
| - * @author White Magic Software, Ltd. | ||
| - */ | ||
| -public class XMLCaretInsertionProcessor extends CaretInsertionProcessor { | ||
| - | ||
| - private final static VTDGen PARSER = new VTDGen(); | ||
| - | ||
| - /** | ||
| - * Constructs a processor capable of inserting a caret marker into XML. | ||
| - * | ||
| - * @param processor The next processor in the chain. | ||
| - * @param position The caret's current position in the text, cannot be null. | ||
| - */ | ||
| - public XMLCaretInsertionProcessor( | ||
| - final Processor<String> processor, | ||
| - final ObservableValue<Integer> position ) { | ||
| - super( processor, position ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Inserts a caret at a valid position within the XML document. | ||
| - * | ||
| - * @param text The string into which caret position marker text is inserted. | ||
| - * | ||
| - * @return The text with a caret position marker included, or the original | ||
| - * text if no insertion point could be found. | ||
| - */ | ||
| - @Override | ||
| - public String processLink( final String text ) { | ||
| - final int caret = getCaretPosition(); | ||
| - int insertOffset = -1; | ||
| - | ||
| - if( text.length() > 0 ) { | ||
| - try { | ||
| - final VTDNav vn = getNavigator( text ); | ||
| - final int tokens = vn.getTokenCount(); | ||
| - | ||
| - int currTokenIndex = 0; | ||
| - int prevTokenIndex = currTokenIndex; | ||
| - int currOffset = 0; | ||
| - | ||
| - // To find the insertion spot even faster, the algorithm could | ||
| - // use a binary search or interpolation search algorithm. This | ||
| - // would reduce the worst-case iterations to O(log n) from O(n). | ||
| - while( currTokenIndex < tokens ) { | ||
| - if( vn.getTokenType( currTokenIndex ) == TOKEN_CHARACTER_DATA ) { | ||
| - final int prevOffset = currOffset; | ||
| - currOffset = vn.getTokenOffset( currTokenIndex ); | ||
| - | ||
| - if( currOffset > caret ) { | ||
| - final int prevLength = vn.getTokenLength( prevTokenIndex ); | ||
| - | ||
| - // If the caret falls within the limits of the previous token, | ||
| - // theninsert the caret position marker at the caret offset. | ||
| - if( isBetween( caret, prevOffset, prevOffset + prevLength ) ) { | ||
| - insertOffset = caret; | ||
| - } else { | ||
| - // The caret position is outside the previous token's text | ||
| - // boundaries, but not inside the current text token. The | ||
| - // caret should be positioned into the closer text token. | ||
| - // For now, the cursor is positioned at the start of the | ||
| - // current text token. | ||
| - insertOffset = currOffset; | ||
| - } | ||
| - | ||
| - break; | ||
| - } | ||
| - | ||
| - prevTokenIndex = currTokenIndex; | ||
| - } | ||
| - | ||
| - currTokenIndex++; | ||
| - } | ||
| - | ||
| - } catch( final Exception ex ) { | ||
| - throw new RuntimeException( | ||
| - new ParseException( ex.getMessage(), caret ) | ||
| - ); | ||
| - } | ||
| - } | ||
| - | ||
| - return inject( text, insertOffset ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Parses the given XML document and returns a high-performance navigator | ||
| - * instance for scanning through the XML elements. | ||
| - * | ||
| - * @param xml The XML document to parse. | ||
| - * | ||
| - * @return A document navigator instance. | ||
| - */ | ||
| - private VTDNav getNavigator( final String xml ) throws VTDException { | ||
| - final VTDGen vg = getParser(); | ||
| - | ||
| - // XML recommends UTF-8 encoding. | ||
| - // See: http://stackoverflow.com/a/36696214/59087 | ||
| - // | ||
| - // The encoding should be derived, not assumed. | ||
| - vg.setDoc( xml.getBytes( UTF_8 ) ); | ||
| - vg.parse( true ); | ||
| - return vg.getNav(); | ||
| - } | ||
| - | ||
| - private synchronized VTDGen getParser() { | ||
| - return PARSER; | ||
| - } | ||
| -} | ||