Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
M .gitignore
1313
tex
1414
spell
15
keenwrite.github.io
1516
M build.gradle
5959
  def v_junit = '5.9.0'
6060
  def v_flexmark = '0.64.0'
61
  def v_jackson = '2.13.3'
62
  def v_batik = '1.14'
61
  def v_jackson = '2.13.4'
6362
  def v_echosvg = '0.2.1'
6463
...
8584
  implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${v_jackson}"
8685
  implementation 'org.yaml:snakeyaml:1.30'
87
88
  // XML
89
  //implementation 'com.ximpleware:vtd-xml:2.13.4'
9086
9187
  // HTML parsing and rendering
M libs/keenquotes.jar
Binary file
M src/main/java/com/keenwrite/dom/DocumentParser.java
3838
    "{http://xml.apache.org/xslt}indent-amount";
3939
40
  private static final ByteArrayOutputStream sWriter =
41
    new ByteArrayOutputStream( 65536 );
42
  private static final OutputStreamWriter sOutput =
43
    new OutputStreamWriter( sWriter );
44
4045
  /**
4146
   * Caches {@link XPathExpression}s to avoid re-compiling.
...
215220
    assert path != null;
216221
217
    final var writer = new ByteArrayOutputStream( 65536 );
218
    final var output = new OutputStreamWriter( writer );
219
    final var target = new StreamResult( output );
222
    // Preprocessing the SVG image is a single-threaded operation, no matter
223
    // how many SVG images are in the document to typeset.
224
    sWriter.reset();
225
226
    final var target = new StreamResult( sOutput );
220227
    final var source = sDocumentBuilder.parse( path.toFile() );
221228
222229
    transform( source, target );
223
    output.close();
224
    write( path, writer.toByteArray() );
225
    writer.close();
230
    write( path, sWriter.toByteArray() );
226231
  }
227232
M src/main/java/com/keenwrite/processors/XhtmlProcessor.java
2222
import static com.keenwrite.util.ProtocolScheme.getProtocol;
2323
import static com.whitemagicsoftware.keenquotes.lex.FilterType.FILTER_XML;
24
import static com.whitemagicsoftware.keenquotes.parser.Curler.CHARS;
2524
import static java.lang.String.format;
2625
import static java.lang.String.valueOf;
...
3534
public final class XhtmlProcessor extends ExecutorProcessor<String> {
3635
  private final static Curler sTypographer =
37
    new Curler( contractions(), CHARS, FILTER_XML );
36
    new Curler( createContractions(), FILTER_XML, true );
3837
3938
  private final ProcessorContext mContext;
...
188187
      }
189188
190
      // Strip comments, superfluous whitespace, DOCTYPE, and XML declarations.
191189
      if( mediaType.isSvg() ) {
192190
        DocumentParser.sanitize( imageFile );
...
284282
   * @return List of contractions to use for curling straight quotes.
285283
   */
286
  private static Contractions contractions() {
284
  private static Contractions createContractions() {
287285
    return new Contractions.Builder().build();
288286
  }
M src/main/java/com/keenwrite/processors/markdown/extensions/fences/FencedBlockExtension.java
4444
   */
4545
  private final static String R_SVG_EXPORT =
46
    "tryCatch({svg('%s')%n%s%n},finally={dev.off()})%n";
46
    "tryCatch({svg('%s'%s)%n%s%n},finally={dev.off()})%n";
4747
4848
  private final static String STYLE_DIAGRAM = "diagram-";
...
181181
    }
182182
183
    /**
184
     * Evaluates an R expression. This will take into consideration any
185
     * key/value pairs passed in from the document, such as width and height
186
     * attributes of the form: <code>{r width=5 height=5}</code>.
187
     *
188
     * @param node    The {@link FencedCodeBlock} to evaluate using R.
189
     * @param context Used to resolve the link that refers to any resulting
190
     *                image produced by the R chunk (such as a plot).
191
     * @return The SVG text string associated with the content produced by
192
     * the chunk (such as a graphical data plot).
193
     */
194
    @SuppressWarnings( "unused" )
183195
    private Tuple<String, ResolvedLink> evaluateRChunk(
184196
      final FencedCodeBlock node,
185197
      final NodeRendererContext context ) {
186198
      final var content = node.getContentChars().normalizeEOL().trim();
187199
      final var text = mRVariableProcessor.apply( content );
188200
      final var hash = Integer.toHexString( text.hashCode() );
189201
      final var filename = format( "%s-%s.svg", APP_TITLE_LOWERCASE, hash );
190202
      final var svg = Paths.get( TEMP_DIR, filename ).toString();
191203
      final var link = context.resolveLink( LINK, svg, false );
192
      final var r = format( R_SVG_EXPORT, svg, text );
204
      final var dimensions = getAttributes( node.getInfo() );
205
      final var r = format( R_SVG_EXPORT, svg, dimensions, text );
193206
      final var result = mRChunkEvaluator.apply( r );
194207
195208
      return new Tuple<>( svg, link );
209
    }
210
211
    /**
212
     * Splits attributes of the form <code>{r key1=value2 key2=value2}</code>
213
     * into a comma-separated string containing only the key/value pairs,
214
     * such as <code>key1=value1,key2=value2</code>.
215
     *
216
     * @param bs The complete line after the fenced block demarcation.
217
     * @return A comma-separated string of name/value pairs.
218
     */
219
    private String getAttributes( final BasedSequence bs ) {
220
      final var result = new StringBuilder();
221
      final var split = bs.splitList( " " );
222
      final var splits = split.size();
223
224
      for( var i = 1; i < splits; i++ ) {
225
        final var based = split.get( i ).toString();
226
        final var attribute = based.replace( '}', ' ' );
227
228
        // The order of attribute evaluations is in order of performance.
229
        if( !attribute.isBlank() &&
230
          attribute.indexOf( '=' ) > 1 &&
231
          attribute.matches( ".*\\d.*" ) ) {
232
233
          // The comma will do double-duty for separating individual attributes
234
          // as well as being the comma that separates all attributes from the
235
          // SVG image file name.
236
          result.append( ',' ).append( attribute );
237
        }
238
      }
239
240
      return result.toString();
196241
    }
197242