Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Remove caret insertion processing

AuthorDaveJarvis <email>
Date2020-06-15 20:54:40 GMT-0700
Commit31e5d939472257d9826b33855c757f4b12aa8efd
Parent64223e0
Delta19 lines added, 484 lines removed, 465-line decrease
src/main/java/com/scrivenvar/processors/markdown/MarkdownCaretInsertionProcessor.java
-/*
- * 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:
- //
- // ![Screenshot](images/scr|eenshot.png)
- //
- // 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 );
- }
-}
src/main/java/com/scrivenvar/processors/CaretReplacementProcessor.java
-/*
- * 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() );
- }
-}
src/main/java/com/scrivenvar/processors/ProcessorFactory.java
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;
}
}
src/main/java/com/scrivenvar/processors/RMarkdownCaretInsertionProcessor.java
-/*
- * 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 );
- }
-}
src/main/java/com/scrivenvar/processors/XMLCaretInsertionProcessor.java
-/*
- * 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;
- }
-}