All Downloads are FREE. Search and download functionalities are using the official Maven repository.

personthecat.catlib.linting.JelHighlighter Maven / Gradle / Ivy

Go to download

Utilities for serialization, commands, noise generation, IO, and some new data types.

The newest version!
package personthecat.catlib.linting;

import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.Nullable;
import xjs.comments.CommentStyle;
import xjs.jel.exception.JelException;
import xjs.jel.sequence.JelType;
import xjs.jel.sequence.Sequence;
import xjs.jel.serialization.sequence.Sequencer;
import xjs.serialization.Span;
import xjs.serialization.token.CommentToken;
import xjs.serialization.token.ContainerToken;
import xjs.serialization.token.ParsedToken;
import xjs.serialization.token.TokenType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import net.minecraft.class_124;
import net.minecraft.class_2561;
import net.minecraft.class_2583;
import net.minecraft.class_2585;

import static personthecat.catlib.linting.SyntaxLinter.color;
import static personthecat.catlib.linting.SyntaxLinter.error;
import static personthecat.catlib.linting.SyntaxLinter.stc;

public class JelHighlighter implements SyntaxLinter.Highlighter {

    public static final Object TODO_MARKER = new Object();
    public static final Pattern TODO_PATTERN =
        Pattern.compile("^\\s*todo\\s*:.*", Pattern.CASE_INSENSITIVE);

    public static final Map DEFAULT_STYLE_MAP =
        ImmutableMap.builder()
            .put(JelType.KEY, color(class_124.field_1076))
            .put(JelType.CALL, color(class_124.field_1054).method_10978(true))
            .put(JelType.REFERENCE, color(class_124.field_1076))
            .put(JelType.REFERENCE_EXPANSION, color(class_124.field_1076))
            .put(JelType.FLAG, color(class_124.field_1065))
            .put(JelType.IMPORT, color(class_124.field_1065))
            .put(JelType.MATCH, color(class_124.field_1065))
            .put(JelType.DELEGATE, color(class_124.field_1054))
            .put(JelType.BOOLEAN, color(class_124.field_1065))
            .put(JelType.INDEX, color(class_124.field_1075))
            .put(JelType.NUMBER, color(class_124.field_1075))
            .put(TokenType.NUMBER, color(class_124.field_1075))
            .put(JelType.NULL, color(class_124.field_1061))
            .put(TokenType.STRING, color(class_124.field_1060))
            .put(JelType.STRING, color(class_124.field_1060))
            .put(CommentStyle.BLOCK, color(class_124.field_1080).method_10978(true))
            .put(CommentStyle.LINE, color(class_124.field_1080).method_10978(true))
            .put(CommentStyle.HASH, color(class_124.field_1080).method_10978(true))
            .put(CommentStyle.LINE_DOC, color(class_124.field_1060).method_10978(true))
            .put(CommentStyle.MULTILINE_DOC, color(class_124.field_1060).method_10978(true))
            .put(TODO_MARKER, color(class_124.field_1054).method_10978(true))
            .build();

    protected final Map styleMap;

    public JelHighlighter() {
        this(DEFAULT_STYLE_MAP);
    }

    public JelHighlighter(final Map styleMap) {
        this.styleMap = styleMap;
    }

    @Override
    public Instance get(final String text) {
        try {
            final Sequence sequence = Sequencer.JEL.parse(text);
            final List> spans = new ArrayList<>();
            trueFlatten(spans, sequence);
            return new JelHighlighterInstance(this.styleMap, spans, text);
        } catch (final JelException e) {
            return new ExceptionHighlighterInstance(e, text);
        }
    }

    protected static void trueFlatten(final List> spans, final Sequence sequence) {
        for (final Span flat : sequence.flatten()) {
            if (flat instanceof ContainerToken container) {
                trueFlatten(spans, container);
            } else if (flat.type() != TokenType.BREAK && flat.length() > 0) {
                spans.add(flat);
            }
        }
    }

    protected static void trueFlatten(final List> spans, final ContainerToken container) {
        for (final Span s : container.viewTokens()) {
            if (s instanceof ContainerToken inner) {
                trueFlatten(spans, inner);
            } else if (s.type() != TokenType.BREAK && s.length() > 0) {
                spans.add(s);
            }
        }
    }

    protected static Object trueType(final Span span) {
        if (span instanceof CommentToken c) {
            if (TODO_PATTERN.matcher(c.parsed()).matches()) {
                return TODO_MARKER;
            }
            return c.commentStyle();
        } else if (span.type() == TokenType.WORD && span instanceof ParsedToken p) {
            return switch (p.parsed()) {
                case "true", "false" -> JelType.BOOLEAN;
                case "null" -> JelType.NULL;
                default -> TokenType.WORD;
            };
        }
        return span.type();
    }

    public static class ExceptionHighlighterInstance implements Instance {
        protected final JelException ex;
        protected final List> spans;
        protected final String text;
        protected final String msg;
        protected @Nullable Span current;
        protected int index;

        protected ExceptionHighlighterInstance(final JelException ex, final String text) {
            this.ex = ex;
            this.spans = ex.getSpans().computeIfAbsent(null, k -> Collections.emptyList());
            this.text = text;
            this.msg = ex.getMessage() + "\n" + ex.getDetails();
            this.next();
        }

        @Override
        public void next() {
            if (this.index < this.spans.size()) {
                this.current = this.spans.get(this.index++);
            } else {
                this.current = null;
            }
        }

        @Override
        public boolean found() {
            return this.current != null;
        }

        @Override
        public int start() {
            return Objects.requireNonNull(this.current).start();
        }

        @Override
        public int end() {
            return Objects.requireNonNull(this.current).end();
        }

        @Override
        public class_2561 replacement() {
            final Span s = Objects.requireNonNull(this.current);
            return stc(s.textOf(this.text)).method_27696(error(this.msg));
        }
    }

    public static class JelHighlighterInstance implements Instance {
        protected final Map styleMap;
        protected final List> spans;
        protected final String text;
        protected @Nullable Span current;
        protected int index;

        protected JelHighlighterInstance(
                final Map styleMap,
                final List> spans,
                final String text) {
            this.styleMap = styleMap;
            this.spans = spans;
            this.text = text;
            this.next();
        }

        @Override
        public void next() {
            if (this.index < this.spans.size()) {
                this.current = this.spans.get(this.index++);
            } else {
                this.current = null;
            }
        }

        @Override
        public boolean found() {
            return this.current != null;
        }

        @Override
        public int start() {
            return Objects.requireNonNull(this.current).start();
        }

        @Override
        public int end() {
            return Objects.requireNonNull(this.current).end();
        }

        @Override
        public class_2561 replacement() {
            final Span s = Objects.requireNonNull(this.current);
            final class_2583 style = this.styleMap.get(trueType(s));
            final class_2585 replacement = stc(s.textOf(this.text));
            return style != null ? replacement.method_27696(style) : replacement;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy