Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
M BUILD.md
77
Download and install the following software packages:
88
9
* [JDK 21](https://bell-sw.com/pages/downloads) (Full JDK + JavaFX)
10
* [Gradle 8.5](https://gradle.org/releases)
11
* [Git 2.43](https://git-scm.com/downloads)
9
* [JDK 22](https://bell-sw.com/pages/downloads) (Full JDK + JavaFX)
10
* [Gradle 8.9](https://gradle.org/releases)
11
* [Git 2.45](https://git-scm.com/downloads)
1212
* [warp v0.4.0-alpha](https://github.com/Reisz/warp/releases/tag/v0.4.0)
1313
M build.gradle
99
  }
1010
  dependencies {
11
    classpath 'org.owasp:dependency-check-gradle:9.0.1'
12
    classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:5.2.4"
11
    classpath 'org.owasp:dependency-check-gradle:10.0.3'
12
    classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.19"
1313
  }
1414
}
1515
1616
plugins {
1717
  id 'application'
1818
  id 'org.openjfx.javafxplugin' version '0.1.0'
19
  id 'com.palantir.git-version' version '3.0.0'
19
  id 'com.palantir.git-version' version '3.1.0'
2020
  id 'com.github.spotbugs' version '6.0.9'
2121
}
...
4242
    content {
4343
      includeGroup 'com.github.css4j'
44
      includeGroup 'io.sf.graphics'
4445
      includeGroup 'io.sf.carte'
4546
      includeGroup 'io.sf.jclf'
...
7879
7980
java {
80
  sourceCompatibility = 21
81
  targetCompatibility = 21
81
  sourceCompatibility = 22
82
  targetCompatibility = 22
8283
}
8384
8485
javafx {
8586
  version = '21'
8687
  modules = ['javafx.base', 'javafx.controls', 'javafx.graphics', 'javafx.swing']
8788
  configuration = 'compileOnly'
8889
}
8990
9091
dependencies {
91
  def v_junit = '5.10.2'
92
  def v_junit = '5.10.3'
9293
  def v_flexmark = '0.64.8'
93
  def v_jackson = '2.17.0'
94
  def v_echosvg = '1.0.1'
95
  def v_picocli = '4.7.5'
94
  def v_jackson = '2.17.2'
95
  def v_echosvg = '1.2'
96
  def v_picocli = '4.7.6'
9697
9798
  // JavaFX
98
  implementation 'org.controlsfx:controlsfx:11.2.0'
99
  implementation 'org.fxmisc.richtext:richtextfx:0.11.2'
100
  implementation 'org.fxmisc.flowless:flowless:0.7.2'
99
  implementation 'org.controlsfx:controlsfx:11.2.1'
100
  implementation 'org.fxmisc.richtext:richtextfx:0.11.3'
101
  implementation 'org.fxmisc.flowless:flowless:0.7.3'
101102
  implementation 'org.fxmisc.wellbehaved:wellbehavedfx:0.3.3'
102103
  implementation 'com.dlsc.preferencesfx:preferencesfx-core:11.17.0'
103
  implementation 'com.panemu:tiwulfx-dock:0.2'
104
  implementation 'com.panemu:tiwulfx-dock:0.3'
104105
105106
  // Markdown
...
119120
120121
  // HTML parsing and rendering
121
  implementation 'org.jsoup:jsoup:1.17.1'
122
  implementation 'org.xhtmlrenderer:flying-saucer-core:9.7.1'
122
  implementation 'org.jsoup:jsoup:1.18.1'
123
  implementation 'org.xhtmlrenderer:flying-saucer-core:9.9.0'
123124
124125
  // R
125126
  implementation 'org.apache.commons:commons-compress:1.26.1'
126
  implementation 'org.codehaus.plexus:plexus-utils:4.0.0'
127
  implementation 'org.codehaus.plexus:plexus-utils:4.0.1'
127128
  implementation 'org.renjin:renjin-script-engine:3.5-beta76'
128129
  implementation 'org.renjin.cran:rjson:0.2.15-renjin-21'
...
144145
  // Misc.
145146
  implementation 'org.ahocorasick:ahocorasick:0.6.3'
146
  implementation 'com.github.albfernandez:juniversalchardet:2.4.0'
147
  implementation 'jakarta.validation:jakarta.validation-api:3.0.2'
147
  implementation 'com.github.albfernandez:juniversalchardet:2.5.0'
148
  implementation 'jakarta.validation:jakarta.validation-api:3.1.0'
148149
  implementation 'org.greenrobot:eventbus-java:3.3.1'
149150
...
166167
  testImplementation "org.junit.jupiter:junit-jupiter-params:${v_junit}"
167168
  testImplementation 'org.testfx:testfx-junit5:4.0.18'
168
  testImplementation 'org.assertj:assertj-core:3.25.3'
169
  testImplementation 'org.assertj:assertj-core:3.26.3'
169170
  testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
170171
}
M docs/references.md
2727
2828
```
29
![image title](https://placekitten.com/600/350)
29
![image title](https://loremflickr.com/600/350)
3030
3131
:: Figure caption text
...
7575
7676
```
77
In [@fig:kitten], a cute kitten is shown.
77
In [@fig:animal], a cute animal is shown.
7878
79
![image title](https://placekitten.com/600/350)
79
![image title](https://loremflickr.com/600/350)
8080
81
:: World's cutest kitten {#fig:kitten}
81
:: World's cutest animal {#fig:animal}
8282
83
There is no cuter kitten than the one in [@fig:kitten].
83
There is no cuter animal than the one in [@fig:animal].
8484
```
8585
...
103103
generated by the typesetting system:
104104
105
| Type name | English name
106
|---|---|
107
| algorithm | Algorithm |
108
| alg | Algorithm |
109
| equation | Equation |
110
| eqn | Equation |
111
| eq | Equation |
112
| figure | Figure |
113
| fig | Figure |
114
| formula | Formula |
115
| listing | Listing |
116
| list | Listing |
117
| lst | Listing |
118
| lyric | Lyrics |
119
| music | Score |
120
| score | Score |
121
| source | Listing |
122
| src | Listing |
123
| tab | Table |
124
| table | Table |
125
| tbl | Table |
105
| Type name | English name |
106
|-----------|--------------|
107
| algorithm | Algorithm    |
108
| alg       | Algorithm    |
109
| equation  | Equation     |
110
| eqn       | Equation     |
111
| eq        | Equation     |
112
| figure    | Figure       |
113
| fig       | Figure       |
114
| formula   | Formula      |
115
| listing   | Listing      |
116
| list      | Listing      |
117
| lst       | Listing      |
118
| lyric     | Lyrics       |
119
| music     | Score        |
120
| score     | Score        |
121
| source    | Listing      |
122
| src       | Listing      |
123
| tab       | Table        |
124
| table     | Table        |
125
| tbl       | Table        |
126126
127127
These values are defined in the theme's `xhtml/xml-references.tex` file.
128
129128
M src/main/java/com/keenwrite/editors/TextResource.java
66
77
import com.keenwrite.io.MediaType;
8
import com.keenwrite.util.EncodingDetector;
89
import javafx.beans.property.ReadOnlyBooleanProperty;
910
import javafx.scene.Node;
10
import org.mozilla.universalchardet.UniversalDetector;
1111
1212
import java.io.File;
1313
import java.nio.charset.Charset;
1414
import java.nio.file.Path;
1515
1616
import static com.keenwrite.constants.Constants.DEFAULT_CHARSET;
1717
import static com.keenwrite.events.StatusEvent.clue;
1818
import static com.keenwrite.io.SysFile.toFile;
19
import static java.nio.charset.Charset.forName;
2019
import static java.nio.file.Files.readAllBytes;
2120
import static java.nio.file.Files.write;
2221
import static java.util.Arrays.asList;
23
import static java.util.Locale.ENGLISH;
2422
2523
/**
...
219217
220218
  private Charset detectEncoding( final byte[] bytes ) {
221
    final var detector = new UniversalDetector( null );
222
    detector.handleData( bytes, 0, bytes.length );
223
    detector.dataEnd();
224
225
    final var detectedCharset = detector.getDetectedCharset();
226
227
    // TODO: Revert when the issue has been fixed.
228
    // https://github.com/albfernandez/juniversalchardet/issues/35
229
    return switch( detectedCharset ) {
230
      case null -> DEFAULT_CHARSET;
231
      case "US-ASCII", "TIS620" -> DEFAULT_CHARSET;
232
      default -> forName( detectedCharset.toUpperCase( ENGLISH ) );
233
    };
219
    return new EncodingDetector().detect( bytes );
234220
  }
235221
M src/main/java/com/keenwrite/editors/definition/yaml/YamlTreeTransformer.java
1818
1919
/**
20
 * Transforms a JsonNode hierarchy into a tree that can be displayed in a user
21
 * interface and vice-versa.
20
 * Transforms a {@link JsonNode} hierarchy into a tree that can be displayed
21
 * in a user interface and vice-versa.
2222
 */
2323
public final class YamlTreeTransformer implements TreeTransformer {
...
9898
    // If the current item has more than one non-leaf child, it's an
9999
    // object node and must become a new nested object.
100
    if( !(children.size() == 1 && children.get( 0 ).isLeaf()) ) {
100
    if( !(children.size() == 1 && children.getFirst().isLeaf()) ) {
101101
      node = node.putObject( item.getValue() );
102102
    }
M src/main/java/com/keenwrite/processors/r/Engine.java
4444
   */
4545
  public static String eval( final String r ) {
46
    return sCache.computeIfAbsent( r, __ -> evaluate( r ) );
46
    return sCache.computeIfAbsent( r, _ -> evaluate( r ) );
4747
  }
4848
M src/main/java/com/keenwrite/ui/tree/AltTreeView.java
2424
2525
    setEditable( true );
26
    setCellFactory( treeView -> new AltTreeCell<>( converter ) );
26
    setCellFactory( _ -> new AltTreeCell<>( converter ) );
2727
    setShowRoot( false );
2828
2929
    // When focus is lost while not editing, deselect all items.
30
    focusedProperty().addListener( ( c, o, n ) -> {
30
    focusedProperty().addListener( ( _, o, _ ) -> {
3131
      if( o && getEditingItem() == null ) {
3232
        getSelectionModel().clearSelection();
M src/main/java/com/keenwrite/ui/tree/TreeItemConverter.java
44
import javafx.util.StringConverter;
55
6
import static com.keenwrite.util.Strings.sanitize;
7
68
/**
79
 * Responsible for converting objects to and from string instances. The
...
1921
  public String fromString( final String string ) {
2022
    return sanitize( string );
21
  }
22
23
  private String sanitize( final String string ) {
24
    return string == null ? "" : string;
2523
  }
2624
}
A src/main/java/com/keenwrite/util/EncodingDetector.java
1
/* Copyright 2024 White Magic Software, Ltd. -- All rights reserved.
2
 *
3
 * SPDX-License-Identifier: MIT
4
 */
5
package com.keenwrite.util;
6
7
import org.mozilla.universalchardet.UniversalDetector;
8
9
import java.nio.charset.Charset;
10
11
import static com.keenwrite.constants.Constants.DEFAULT_CHARSET;
12
import static java.nio.charset.Charset.forName;
13
import static java.util.Locale.ENGLISH;
14
15
/**
16
 * Wraps the {@link UniversalDetector} with to provide enhanced abilities
17
 * and bug fixes (if needed).
18
 */
19
public class EncodingDetector {
20
21
  private final UniversalDetector mDetector;
22
23
  public EncodingDetector() {
24
    mDetector = new UniversalDetector( null );
25
  }
26
27
  /**
28
   * Returns the character set for the constructed input. This will coerce
29
   * both US-ASCII and TIS620 to UTF-8.
30
   *
31
   * @param bytes The textual content having an as yet unknown encoding.
32
   * @return The character encoding for the given bytes.
33
   */
34
  public Charset detect( final byte[] bytes ) {
35
    mDetector.handleData( bytes, 0, bytes.length );
36
    mDetector.dataEnd();
37
38
    final String detectedCharset = mDetector.getDetectedCharset();
39
40
    // TODO: Revert when the issue has been fixed.
41
    // https://github.com/albfernandez/juniversalchardet/issues/35
42
    return switch( detectedCharset ) {
43
      case null -> DEFAULT_CHARSET;
44
      case "US-ASCII", "TIS620" -> DEFAULT_CHARSET;
45
      default -> forName( detectedCharset.toUpperCase( ENGLISH ) );
46
    };
47
  }
48
}
149
M src/main/resources/lexicons/en.txt
Binary file
M src/test/java/com/keenwrite/encoding/EncodingTest.java
11
package com.keenwrite.encoding;
22
3
import com.keenwrite.util.EncodingDetector;
34
import org.junit.jupiter.api.Test;
4
import org.mozilla.universalchardet.UniversalDetector;
55
66
import java.nio.charset.Charset;
77
import java.nio.charset.StandardCharsets;
88
9
import static java.nio.charset.StandardCharsets.*;
910
import static org.junit.jupiter.api.Assertions.assertEquals;
10
import static org.junit.jupiter.api.Assertions.assertNotNull;
1111
1212
public class EncodingTest {
1313
  @Test
14
  @SuppressWarnings( "UnnecessaryLocalVariable" )
1415
  public void test_Encoding_UTF8_UTF8() {
1516
    final var bytes = testBytes();
16
17
    final var detector = new UniversalDetector( null );
18
    detector.handleData( bytes, 0, bytes.length );
19
    detector.dataEnd();
20
21
    final var expectedCharset = StandardCharsets.UTF_8;
22
    final var detectedCharset = detector.getDetectedCharset();
23
24
    assertNotNull( detectedCharset );
25
26
    final var actualCharset = Charset.forName( detectedCharset );
17
    final var detector = new EncodingDetector();
18
    final var expectedCharset = UTF_8;
19
    final var actualCharset = detector.detect( bytes );
2720
2821
    assertEquals( expectedCharset, actualCharset );
...
4235
        more relaxing.
4336
        """
44
        .getBytes();
37
        .getBytes( UTF_8 );
4538
  }
4639
}
M src/test/java/com/keenwrite/io/MediaTypeSnifferTest.java
1414
 */
1515
class MediaTypeSnifferTest {
16
1716
  @Test
1817
  void test_Read_KnownFileTypes_MediaTypeReturned()
1918
    throws Exception {
2019
    final var clazz = getClass();
2120
    final var pkgName = clazz.getPackageName();
2221
    final var dir = pkgName.replace( '.', '/' );
2322
24
    final var urls = clazz.getClassLoader().getResources( dir + "/images" );
23
    final var urls = clazz.getClassLoader().getResources( STR."\{dir}/images" );
2524
    assertTrue( urls.hasMoreElements() );
2625
...
3534
        final var actualExtension = valueFrom( media ).getExtension();
3635
        final var expectedExtension = getExtension( image.toString() );
36
        System.out.println( STR."\{image} -> \{media}" );
37
3738
        assertEquals( expectedExtension, actualExtension );
3839
      }
M src/test/java/com/keenwrite/io/MediaTypeTest.java
5353
       "https://kroki.io/robots.txt", TEXT_PLAIN,
5454
       "https://place-hold.it/300x500", IMAGE_GIF,
55
       "https://placekitten.com/g/200/300", IMAGE_JPEG,
55
       "https://loremflickr.com/200/300", IMAGE_JPEG,
5656
       "https://upload.wikimedia.org/wikipedia/commons/9/9f/Vimlogo.svg", IMAGE_SVG_XML,
5757
       "https://kroki.io//graphviz/svg/eNpLyUwvSizIUHBXqPZIzcnJ17ULzy_KSanlAgB1EAjQ", IMAGE_SVG_XML
5858
    );
5959
    //@formatter:on
6060
6161
    map.forEach( ( k, v ) -> {
6262
      try( var response = open( k ) ) {
63
        System.out.printf( "%s => %s%n", k, v );
6364
        assertEquals( v, response.getMediaType() );
6465
      } catch( final Exception e ) {
M src/test/java/com/keenwrite/io/SysFileTest.java
1616
  @Test
1717
  void test_Locate_ExistingExecutable_PathFound() {
18
    testFunction( SysFile::locate, "ls", "/usr/bin/ls" );
18
    testFunction( SysFile::locate, "env", "/usr/bin/env" );
1919
  }
2020
M src/test/java/com/keenwrite/processors/html/XhtmlProcessorTest.java
7272
        XHTML_TEX,
7373
        """
74
          <html><head><title/><meta content="2" name="count"/></head><body><p>the 👍 emoji</p>
74
          <html><head><title/><meta charset="UTF-8"/><meta content="2" name="count"/></head><body><p>the 👍 emoji</p>
7575
          </body></html>"""
7676
      )
M src/test/java/com/keenwrite/processors/markdown/extensions/images/ImageLinkExtensionTest.java
3535
  private static final String PATH_KITTEN_JPG = STR."\{URI_PATH}.jpg";
3636
37
  /** Web server that doles out images. */
38
  private static final String PLACEHOLDER = "loremflickr.com";
39
3740
  private static final Map<String, String> IMAGES = new LinkedHashMap<>();
3841
3942
  static {
4043
    add( PATH_KITTEN_PNG, URI_PATH );
4144
    add( PATH_KITTEN_PNG, URI_FILE );
4245
    add( PATH_KITTEN_PNG, PATH_KITTEN_PNG );
4346
    add( PATH_KITTEN_JPG, PATH_KITTEN_JPG );
44
    add( "//placekitten.com/200/200", "//placekitten.com/200/200" );
45
    add( "ftp://placekitten.com/200/200", "ftp://placekitten.com/200/200" );
46
    add( "http://placekitten.com/200/200", "http://placekitten.com/200/200" );
47
    add( "https://placekitten.com/200/200", "https://placekitten.com/200/200" );
47
    add( STR."//\{PLACEHOLDER}/200/200", STR."//\{PLACEHOLDER}/200/200" );
48
    add( STR."ftp://\{PLACEHOLDER}/200/200",  STR."ftp://\{PLACEHOLDER}/200/200" );
49
    add( STR."http://\{PLACEHOLDER}/200/200", STR."http://\{PLACEHOLDER}/200/200" );
50
    add( STR."https://\{PLACEHOLDER}/200/200", STR."https://\{PLACEHOLDER}/200/200" );
4851
  }
4952
M src/test/java/com/keenwrite/processors/markdown/extensions/references/CaptionsAndCrossReferencesExtensionTest.java
176176
      args(
177177
        """
178
          ![kitteh](placekitten)
178
          ![kitteh](kitten)
179179
180180
          :: Caption **bold** {#fig:label} *italics*
181181
          """,
182182
        """
183183
          <p><span class="caption">Caption <strong>bold</strong>  <em>italics</em></span><a class="name" data-type="fig" name="label" /></p>
184
          <p><img src="placekitten" alt="kitteh" /></p>
184
          <p><img src="kitten" alt="kitteh" /></p>
185185
          """
186186
      ),