Giter Club home page Giter Club logo

prism4j's Introduction

Prism4j

Simplified Java clone of prism-js. No rendering, no themes, no hooks, no plugins. But still a language parsing. Primary aim of this library is to provide a tokenization strategy of arbitrary syntaxes for later processing. Works on Android (great with Markwon - markdown display library).

Core

Core module prism4j is a lightweight module that comes with API (no language definitions).

prism4j

implementation "io.noties:prism4j:${prism_version}"
final Prism4j prism4j = new Prism4j(new MyGrammarLocator());
final Grammar grammar = prism4j.grammar("json");
if (grammar != null) {
    final List<Node> nodes = prism4j.tokenize(code, grammar);
    final AbsVisitor visitor = new AbsVisitor() {
            @Override
            protected void visitText(@NonNull Prism4j.Text text) {
                // raw text
                text.literal();
            }

            @Override
            protected void visitSyntax(@NonNull Prism4j.Syntax syntax) {
                // type of the syntax token
                syntax.type();
                visit(syntax.children());
            }
        };
    visitor.visit(nodes);
}

Where MyGrammarLocator can be as simple as:

public class MyGrammarLocator implements GrammarLocator {

    @Nullable
    @Override
    public Prism4j.Grammar grammar(@NonNull Prism4j prism4j, @NonNull String language) {
        switch (language) {

            case "json":
                return Prism_json.create(prism4j);

            // everything else is omitted

            default:
                return null;
        }
    }
}

And language definition:

import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.compile;
import static io.noties.prism4j.Prism4j.grammar;
import static io.noties.prism4j.Prism4j.pattern;
import static io.noties.prism4j.Prism4j.token;

@Aliases("jsonp")
public class Prism_json {

  @NonNull
  public static Prism4j.Grammar create(@NonNull Prism4j prism4j) {
    return grammar(
      "json",
      token("property", pattern(compile("\"(?:\\\\.|[^\\\\\"\\r\\n])*\"(?=\\s*:)", CASE_INSENSITIVE))),
      token("string", pattern(compile("\"(?:\\\\.|[^\\\\\"\\r\\n])*\"(?!\\s*:)"), false, true)),
      token("number", pattern(compile("\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:[Ee][+-]?\\d+)?"))),
      token("punctuation", pattern(compile("[{}\\[\\]);,]"))),
      token("operator", pattern(compile(":"))),
      token("boolean", pattern(compile("\\b(?:true|false)\\b", CASE_INSENSITIVE))),
      token("null", pattern(compile("\\bnull\\b", CASE_INSENSITIVE)))
    );
  }
}

Bundler

In order to simplify adding language definitions to your project there is a special module called prism4j-bundler that will automatically add requested languages.

prism4j-bundler

annotationProcessor 'io.noties:prism4j-bundler:${prism_version}'

Please note that bundler can add languages that are ported (see ./languages folder for the list). Currently it supports:

  • brainf*ck
  • c
  • clike
  • clojure
  • cpp
  • csharp (dotnet)
  • css (+css-extras)
  • dart
  • git
  • go
  • groovy (no string interpolation)
  • java
  • javascript (js)
  • json (jsonp)
  • kotlin
  • latex
  • makefile
  • markdown
  • markup (xml, html, mathml, svg)
  • python
  • scala
  • sql
  • swift
  • yaml

Please see Contributing section if you wish to port a language.

@PrismBundle(
    includes = { "clike", "java", "c" },
    grammarLocatorClassName = ".MyGrammarLocator"
)
public class MyClass {}

You can have multiple language bundles, just annotate different classes in your project. There are no special requirements for a class to be annotated (in can be any class in your project).

  • includes - indicates what supported languages to add to your project. Please use real language name (not an alias). So javascript instead of js; markup instead of xml.

  • grammarLocatorClassName - is the Java class name of generated GrammarLocator. It can start with a dot to put generated GrammarLocator to the same package as annotated element. Or be fully qualified Java name (starting with a package).

!important

NB generated GrammarLocator will create languages when they are requested (aka lazy loading). Make sure this works for you by keeping as is or by manually triggering language creation via prism4j.grammar("my-language"); when convenient at runtime.

Contributing

If you want to contribute to this project porting grammar definitions would be the best start. But before you begin please create an issue with language-support tag so others can see that a language is being worked at. This issue will be also the great place to discuss things that could arise whilst in process.

Language definitions are at the /languages folder (go down the io.noties.prism4j.languages package to find the files). A new file should follow simple naming convention: Prism_{real_language_name}.java. So, a definition for the json would be Prism_json.java.

In order to provide bundler with meta-information about a language @Aliases, @Extend and @Modify annotations can be used:

  • @Aliases specifies what aliases a language has. For example markup language has these: @Aliases({"html", "xml", "mathml", "svg"}). So when a GrammarLocator will be asked for a svg language the markup will be returned.
@Aliases({"html", "xml", "mathml", "svg"})
public class Prism_markup {}
  • @Extend annotation indicates if a language definition is a sibling of another one. So even if a parent language is not included in @PrismBundle it will be added to a project anyway. For example, c:
@Extend("clike")
public class Prism_c {}
  • @Modify annotation makes sure that if a language definition modifies another one, modified language will be processed before returning to a caller. This does not include a language that is being modified to a project. But if it's present, it will be modified. For example, css:
@Modify("markup")
public class Prism_css {}

@Modify accepts an array of language names


After you are done (haha!) with a language definition please make sure that you also move test cases from prism-js for the project (for newly added language of cause). Thankfully just a byte of work required here as prism4j-languages module understands native format of prism-js test cases (that are ending with *.test). Please inspect test folder of the prism4j-languages module for further info. In short: copy test cases from prism-js project (the whole folder for specific language) into prism4j-languages/src/test/resources/languages/ folder.

Then, if you run:

./gradlew :prism4j-languages:test

and all tests pass (including your newly added), then it's safe to issue a pull request. Good job!

Important note about regex for contributors

As this project wants to work on Android, your regex's patterns must have } symbol escaped (\\}). Yes, an IDE will warn you that this escape is not needed, but do not believe it. Pattern just won't compile at runtime (Android). I wish this could be unit-tested but unfortunately Robolectric compiles just fine (no surprise actually).

License

  Copyright 2019 Dimitry Ivanov ([email protected])

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

prism4j's People

Contributors

noties avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

prism4j's Issues

kapt task throws warnings about source version being less than '11'

kapt task throws the following warning when a project is built in android studio

Supported source version 'RELEASE_8' from annotation processor 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' less than -source '11'

would be great if the source and target compatibility is updated to VERSION_11 like below:

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

I tried to publish jars locally and use it but the existing grammar locators stopped working.

Side Note:

I saw a comment in the code where you had noted that you were unable to include local projects in the gradle file. That can be fixed by making following changes:

in the settings.gradle in root directory

rootProject.name = 'Prism4jProject'
include 'prism4j'
project(':prism4j').name = "prism4j"
include 'prism4j-languages'
project(':prism4j-languages').name = "prism4j-languages"
include 'prism4j-bundler'
project(':prism4j-bundler').name = "prism4j-bundler"

in the prism4j-bundler module's build.gradle file you can include other local projects like this:

implementation project(path: ':prism4j')

kapt task throws warnings about source version being less than '11'

kapt task throws the following warning when a project is built in android studio

Supported source version 'RELEASE_8' from annotation processor 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' less than -source '11'

would be great if the source and target compatibility is updated to VERSION_11 like below:

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

I tried to publish jars locally and use it but the existing grammar locators stopped working.

Side Note:

I saw a comment in the code where you had noted that you were unable to include local projects in the gradle file. That can be fixed by making following changes:

in the settings.gradle in root directory

rootProject.name = 'Prism4jProject'
include 'prism4j'
project(':prism4j').name = "prism4j"
include 'prism4j-languages'
project(':prism4j-languages').name = "prism4j-languages"
include 'prism4j-bundler'
project(':prism4j-bundler').name = "prism4j-bundler"

in the prism4j-bundler module's build.gradle file you can include other local projects like this:

implementation project(path: ':prism4j')

Prism4j internal error

There will be a crash when the code block has the following content:

<script></script>

Abnormal content:

java.lang.RuntimeException: Prism4j internal error. Number of entry nodes is greater that the text length.
Nodes: [TextImpl{literal=''}]
Text:

This exception can be reproduced when the markup language is 'markup'.

kapt task throws warnings about source version being less than '11'

kapt task throws the following warning when a project is built in android studio

Supported source version 'RELEASE_8' from annotation processor 'org.jetbrains.kotlin.kapt3.base.ProcessorWrapper' less than -source '11'

would be great if the source and target compatibility is updated to VERSION_11 like below:

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

I tried to publish jars locally and use it but the existing grammar locators stopped working.

Side Note:

I saw a comment in the code where you had noted that you were unable to include local projects in the gradle file. That can be fixed by making following changes:

in the settings.gradle in root directory

rootProject.name = 'Prism4jProject'
include 'prism4j'
project(':prism4j').name = "prism4j"
include 'prism4j-languages'
project(':prism4j-languages').name = "prism4j-languages"
include 'prism4j-bundler'
project(':prism4j-bundler').name = "prism4j-bundler"

in the prism4j-bundler module's build.gradle file you can include other local projects like this:

implementation project(path: ':prism4j')

Execution failed for task ':app:javaPreCompileDebug'.

I used Markwon and following error repoted. Any idea? Thanks!

Execution failed for task ':app:javaPreCompileDebug'.
> Could not resolve all files for configuration ':app:debugAnnotationProcessorClasspath'.
   > Could not find prism4j-bundler.jar (io.noties:prism4j-bundler:2.0.0).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/io/noties/prism4j-bundler/2.0.0/prism4j-bundler-2.0.0.jar
   > Could not find ixjava.jar (com.github.akarnokd:ixjava:1.0.0).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/github/akarnokd/ixjava/1.0.0/ixjava-1.0.0.jar
   > Could not find commons-io.jar (commons-io:commons-io:2.6).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/commons-io/commons-io/2.6/commons-io-2.6.jar
   > Could not find google-java-format.jar (com.google.googlejavaformat:google-java-format:1.6).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/googlejavaformat/google-java-format/1.6/google-java-format-1.6.jar
   > Could not find guava.jar (com.google.guava:guava:22.0).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/guava/guava/22.0/guava-22.0.jar
   > Could not find javac-shaded.jar (com.google.errorprone:javac-shaded:9+181-r4173-1).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/errorprone/javac-shaded/9+181-r4173-1/javac-shaded-9+181-r4173-1.jar
   > Could not find jsr305.jar (com.google.code.findbugs:jsr305:1.3.9).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar
   > Could not find error_prone_annotations.jar (com.google.errorprone:error_prone_annotations:2.0.18).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/errorprone/error_prone_annotations/2.0.18/error_prone_annotations-2.0.18.jar
   > Could not find j2objc-annotations.jar (com.google.j2objc:j2objc-annotations:1.1).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar
   > Could not find animal-sniffer-annotations.jar (org.codehaus.mojo:animal-sniffer-annotations:1.14).
     Searched in the following locations:
         http://maven.aliyun.com/nexus/content/repositories/jcenter/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar

Possible solution:
 - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
dependencies {
    implementation "io.noties.markwon:core:4.3.1"
    implementation "io.noties.markwon:ext-strikethrough:4.3.1"
    implementation "io.noties.markwon:ext-latex:4.3.1"
    implementation "io.noties.markwon:editor:4.3.1"
    implementation "io.noties.markwon:image:4.3.1"
    implementation "io.noties.markwon:html:4.3.1"
    implementation "io.noties.markwon:ext-tasklist:4.3.1"
    implementation "io.noties.markwon:syntax-highlight:4.3.1"
    implementation "io.noties:prism4j:2.0.0"
    annotationProcessor 'io.noties:prism4j-bundler:2.0.0'
}
buildscript {
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/google'}
        google()
        jcenter()
    }
}
allprojects {
    repositories {
        maven{ url 'https://maven.aliyun.com/repository/google'}
        google()
        jcenter()
        mavenCentral()
    }
}

Transitive dependencies to org.jetbrains.annotations are causing conflicts

See for example Nextcloud: https://github.com/nextcloud/android/blob/master/build.gradle#L49-L54

Complete error message when building without excluding the transitive dependency:

Duplicate class org.intellij.lang.annotations.Flow found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.Identifier found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$AdjustableOrientation found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$BoxLayoutAxis found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$CalendarMonth found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$CursorType found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$FlowLayoutAlignment found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$FontStyle found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$HorizontalAlignment found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$InputEventMask found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$ListSelectionMode found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$PatternFlags found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TabLayoutPolicy found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TabPlacement found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TitledBorderJustification found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TitledBorderTitlePosition found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TreeSelectionMode found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.Language found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.MagicConstant found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.Pattern found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.PrintFormat found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.PrintFormatPattern found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.RegExp found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.intellij.lang.annotations.Subst found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.Contract found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.Nls found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.NonNls found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.NotNull found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.Nullable found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.PropertyKey found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)
Duplicate class org.jetbrains.annotations.TestOnly found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-17.0 (org.jetbrains:annotations-java5:17.0.0)

(Side note: io.noties.markwon:syntax-highlight:4.6.0 has the same issue)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.