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

org.jline.console.impl.SystemHighlighter Maven / Gradle / Ivy

/*
 * Copyright (c) 2002-2021, the original author or authors.
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 *
 * https://opensource.org/licenses/BSD-3-Clause
 */
package org.jline.console.impl;

import org.jline.builtins.Nano.SyntaxHighlighter;
import org.jline.builtins.Styles;
import org.jline.console.SystemRegistry;
import org.jline.reader.LineReader;
import org.jline.reader.ParsedLine;
import org.jline.reader.Parser;
import org.jline.reader.impl.DefaultHighlighter;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.OSUtils;
import org.jline.utils.StyleResolver;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * Highlight command and language syntax using nanorc highlighter.
 *
 * @author Matti Rinta-Nikkola
 */
public class SystemHighlighter extends DefaultHighlighter {
    private final static StyleResolver resolver = Styles.lsStyle();
    protected final SyntaxHighlighter commandHighlighter;
    protected final SyntaxHighlighter argsHighlighter;
    protected final SyntaxHighlighter langHighlighter;
    protected final SystemRegistry systemRegistry;
    protected final Map fileHighlight = new HashMap<>();

    public SystemHighlighter(SyntaxHighlighter commandHighlighter, SyntaxHighlighter argsHighlighter
            , SyntaxHighlighter langHighlighter) {
        this.commandHighlighter = commandHighlighter;
        this.argsHighlighter = argsHighlighter;
        this.langHighlighter = langHighlighter;
        this.systemRegistry = SystemRegistry.get();
    }

    @Override
    public AttributedString highlight(LineReader reader, String buffer) {
        return doDefaultHighlight(reader) ? super.highlight(reader, buffer) : systemHighlight(reader, buffer);
    }

    public void addFileHighlight(String... commands) {
        for (String c : commands) {
            fileHighlight.put(c, new FileHighlightCommand());
        }
    }

    public void addFileHighlight(String command, String subcommand, Collection fileOptions) {
        fileHighlight.put(command, new FileHighlightCommand(subcommand, fileOptions));
    }

    private boolean doDefaultHighlight(LineReader reader) {
        String search = reader.getSearchTerm();
        return ((search != null && search.length() > 0) || reader.getRegionActive() != LineReader.RegionType.NONE
                || errorIndex > -1 || errorPattern != null);
    }

    protected AttributedString systemHighlight(LineReader reader, String buffer) {
        AttributedString out;
        Parser parser = reader.getParser();
        String command = parser.getCommand(buffer);
        if (buffer.trim().isEmpty()) {
            out = new AttributedStringBuilder().append(buffer).toAttributedString();
        } else if (fileHighlight.containsKey(command)) {
            FileHighlightCommand fhc = fileHighlight.get(command);
            if (!fhc.hasFileOptions()) {
                out = doFileArgsHighlight(reader, buffer, fhc);
            } else {
                out = doFileOptsHighlight(reader, buffer, fhc);
            }
        } else if (systemRegistry.isCommandOrScript(command) || systemRegistry.isCommandAlias(command)) {
            out = doCommandHighlight(buffer);
        } else if (langHighlighter != null) {
            out = langHighlighter.highlight(buffer);
        } else {
            out = new AttributedStringBuilder().append(buffer).toAttributedString();
        }
        return out;
    }

    protected AttributedString doFileOptsHighlight(LineReader reader, String buffer, FileHighlightCommand fhc) {
        int idx0 = commandIndex(buffer);
        AttributedStringBuilder asb = new AttributedStringBuilder();
        if (idx0 < 0) {
            highlightCommand(buffer, asb);
        } else {
            highlightCommand(buffer.substring(0, idx0), asb);
            ParsedLine parsedLine = reader.getParser().parse(buffer, buffer.length() + 1, Parser.ParseContext.COMPLETE);
            List words = parsedLine.words();
            if (!fhc.isSubcommand() || (words.size() > 2 && fhc.getSubcommand().equals(words.get(1)))) {
                int firstArg = fhc.isSubcommand() ? 1 : 0;
                int idx = buffer.indexOf(words.get(firstArg)) + words.get(firstArg).length() + 1;
                highlightArgs(buffer.substring(idx0, idx), asb);
                boolean fileOption = false;
                for (int i = firstArg + 1; i < words.size(); i++) {
                    int nextIdx = buffer.substring(idx).indexOf(words.get(i)) + idx;
                    for (int j = idx; j < nextIdx; j++) {
                        asb.append(buffer.charAt(j));
                    }
                    String word = words.get(i);
                    if (word.contains("=") && fhc.getFileOptions().contains(word.substring(0, word.indexOf("=")))) {
                        highlightArgs(word.substring(0, word.indexOf("=") + 1), asb);
                        highlightFileArg(reader, word.substring(word.indexOf("=") + 1), asb);
                    } else if (fhc.getFileOptions().contains(word)) {
                        highlightArgs(word, asb);
                        fileOption = true;
                    } else if (fileOption) {
                        highlightFileArg(reader, word, asb);
                    } else {
                        highlightArgs(word, asb);
                        fileOption = false;
                    }
                    idx = nextIdx + word.length();
                }
            } else {
                highlightArgs(buffer.substring(idx0), asb);
            }
        }
        return asb.toAttributedString();
    }

    protected AttributedString doFileArgsHighlight(LineReader reader, String buffer, FileHighlightCommand fhc) {
        int idx0 = commandIndex(buffer);
        AttributedStringBuilder asb = new AttributedStringBuilder();
        if (idx0 < 0) {
            highlightCommand(buffer, asb);
        } else {
            highlightCommand(buffer.substring(0, idx0), asb);
            ParsedLine parsedLine = reader.getParser().parse(buffer, buffer.length() + 1, Parser.ParseContext.COMPLETE);
            List words = parsedLine.words();
            if (!fhc.isSubcommand() || (words.size() > 2 && fhc.getSubcommand().equals(words.get(1)))) {
                int firstArg = fhc.isSubcommand() ? 1 : 0;
                int idx = buffer.indexOf(words.get(firstArg)) + words.get(firstArg).length();
                highlightArgs(buffer.substring(idx0, idx), asb);
                for (int i = firstArg + 1; i < words.size(); i++) {
                    int nextIdx = buffer.substring(idx).indexOf(words.get(i)) + idx;
                    for (int j = idx; j < nextIdx; j++) {
                        asb.append(buffer.charAt(j));
                    }
                    highlightFileArg(reader, words.get(i), asb);
                    idx = nextIdx + words.get(i).length();
                }
            } else {
                highlightArgs(buffer.substring(idx0), asb);
            }
        }
        return asb.toAttributedString();
    }

    protected AttributedString doCommandHighlight(String buffer) {
        AttributedString out;
        if (commandHighlighter != null || argsHighlighter != null) {
            int idx = commandIndex(buffer);
            AttributedStringBuilder asb = new AttributedStringBuilder();
            if (idx < 0) {
                highlightCommand(buffer, asb);
            } else {
                highlightCommand(buffer.substring(0, idx), asb);
                highlightArgs(buffer.substring(idx), asb);
            }
            out = asb.toAttributedString();
        } else {
            out = new AttributedStringBuilder().append(buffer).toAttributedString();
        }
        return out;
    }

    private int commandIndex(String buffer) {
        int idx = -1;
        boolean cmdFound = false;
        for (int i = 0; i < buffer.length(); i++) {
            char c = buffer.charAt(i);
            if (c != ' ') {
                cmdFound = true;
            } else if (cmdFound) {
                idx = i;
                break;
            }
        }
        return idx;
    }

    private void highlightFileArg(LineReader reader, String arg, AttributedStringBuilder asb) {
        if (arg.startsWith("-")) {
            highlightArgs(arg, asb);
        } else {
            String separator = reader.isSet(LineReader.Option.USE_FORWARD_SLASH)
                    ? "/" : Paths.get(System.getProperty("user.dir")).getFileSystem().getSeparator();
            StringBuilder sb = new StringBuilder();
            try {
                Path path = new File(arg).toPath();
                Iterator iterator = path.iterator();
                if (OSUtils.IS_WINDOWS && arg.matches("^[A-Za-z]:.*$")) {
                    if (arg.length() == 2) {
                        sb.append(arg);
                        asb.append(arg);
                    } else if (arg.charAt(2) == separator.charAt(0)) {
                        sb.append(arg.substring(0, 3));
                        asb.append(arg.substring(0, 3));
                    }
                }
                if (arg.startsWith(separator)) {
                    sb.append(separator);
                    asb.append(separator);
                }
                while (iterator.hasNext()) {
                    sb.append(iterator.next());
                    highlightFile(new File(sb.toString()).toPath(), asb);
                    if (iterator.hasNext()) {
                        sb.append(separator);
                        asb.append(separator);
                    }
                }
                if (arg.length() > 2 && !arg.matches("^[A-Za-z]:" + separator) && arg.endsWith(separator)) {
                    asb.append(separator);
                }
            } catch (Exception e) {
                asb.append(arg);
            }
        }
    }

    private void highlightFile(Path path, AttributedStringBuilder asb) {
        AttributedStringBuilder sb = new AttributedStringBuilder();
        String name = path.getFileName().toString();
        int idx = name.lastIndexOf(".");
        String type = idx != -1 ? ".*" + name.substring(idx): null;
        if (Files.isSymbolicLink(path)) {
            sb.styled(resolver.resolve(".ln"), name);
        } else if (Files.isDirectory(path)) {
            sb.styled(resolver.resolve(".di"), name);
        } else if (Files.isExecutable(path) && !OSUtils.IS_WINDOWS) {
            sb.styled(resolver.resolve(".ex"), name);
        } else if (type != null && resolver.resolve(type).getStyle() != 0) {
            sb.styled(resolver.resolve(type), name);
        } else if (Files.isRegularFile(path)) {
            sb.styled(resolver.resolve(".fi"), name);
        } else {
            sb.append(name);
        }
        asb.append(sb);
    }

    private void highlightArgs(String args, AttributedStringBuilder asb) {
        if (argsHighlighter != null) {
            asb.append(argsHighlighter.highlight(args));
        } else {
            asb.append(args);
        }
    }

    private void highlightCommand(String command, AttributedStringBuilder asb) {
        if (commandHighlighter != null) {
            asb.append(commandHighlighter.highlight(command));
        } else {
            asb.append(command);
        }
    }

    protected static class FileHighlightCommand {
        private final String subcommand;
        private final List fileOptions = new ArrayList<>();

        public FileHighlightCommand() {
            this(null, new ArrayList<>());
        }

        public FileHighlightCommand(String subcommand, Collection fileOptions) {
            this.subcommand = subcommand;
            this.fileOptions.addAll(fileOptions);
        }

        public boolean isSubcommand() {
            return subcommand != null;
        }

        public boolean hasFileOptions() {
            return !fileOptions.isEmpty();
        }

        public String getSubcommand() {
            return subcommand;
        }

        public List getFileOptions() {
            return fileOptions;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy