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

org.neo4j.shell.log.AnsiFormattedText Maven / Gradle / Ivy

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.shell.log;

import org.fusesource.jansi.Ansi;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * A piece of text which can be rendered with Ansi format codes.
 */
public class AnsiFormattedText
{

    private static final String RED = "RED";
    private static final String YELLOW = "YELLOW";
    private static final String BOLD = "BOLD";
    private static final String DEFAULT_COLOR = "DEFAULT";
    // no mapping means not defined
    private final Map attributes = new HashMap<>();
    // Each piece is formatted separately
    private final LinkedList pieces = new LinkedList<>();
    // can be defined, or undefined. null means undefined.
    private String color;

    /**
     * Return a new map which is a copy of the first map, with the keys/values from the second if they do not override anything already defined in the first
     * map.
     */
    private static  Map mergeMaps( Map primary, Map secondary )
    {
        Map result = new HashMap<>( primary );
        secondary.forEach( result::putIfAbsent );
        return result;
    }

    /**
     * @return a new empty instance
     */
    public static AnsiFormattedText s()
    {
        return new AnsiFormattedText();
    }

    /**
     * @param string to start with, may be null in which case it is ignored
     * @return a new instance containing the unformatted text in string, or empty if it was null
     */
    public static AnsiFormattedText from( String string )
    {
        AnsiFormattedText st = new AnsiFormattedText();
        if ( string != null )
        {
            st.append( string );
        }
        return st;
    }

    /**
     * @return the text as a string including possible formatting, ready for ANSI formatting
     */
    public String formattedString()
    {
        StringBuilder sb = new StringBuilder();
        for ( AnsiFormattedString s : pieces )
        {
            List codes = new ArrayList<>();

            // color
            if ( s.color != null && !DEFAULT_COLOR.equals( s.color ) )
            {
                codes.add( s.color );
            }
            // attributes
            if ( s.attributes.getOrDefault( BOLD, false ) )
            {
                codes.add( BOLD );
            }
            // Only do formatting if we actually have some formatting to apply
            if ( !codes.isEmpty() )
            {
                sb.append( "@|" )
                  .append( String.join( ",", codes ) )
                  .append( " " );
            }
            // string
            sb.append( s.string );
            // Only reset formatting if we actually did some formatting
            if ( !codes.isEmpty() )
            {
                sb.append( "|@" );
            }
        }
        return sb.toString();
    }

    /**
     * @return the text as a string rendered with ANSI escape codes
     */
    public String renderedString()
    {
        return Ansi.ansi().render( formattedString() ).toString();
    }

    /**
     * @return the text as a plain string without any formatting
     */
    public String plainString()
    {
        StringBuilder sb = new StringBuilder();
        pieces.forEach( sb::append );
        return sb.toString();
    }

    /**
     * Append an already formatted string. If any formatting codes are defined, then they will be ignored in favor of this instance's formatting.
     *
     * @param existing text to append using this instance's formatting
     * @return this
     */
    public AnsiFormattedText append( AnsiFormattedText existing )
    {
        existing.pieces.forEach( s -> pieces.add( new AnsiFormattedString( color != null ? color : s.color,
                                                                           mergeMaps( attributes, s.attributes ), s.string ) ) );
        return this;
    }

    /**
     * Append a string using the current formatting
     *
     * @param s string to append using this instance's formatting
     * @return this
     */
    public AnsiFormattedText append( String s )
    {
        pieces.add( new AnsiFormattedString( color, attributes, s ) );
        return this;
    }

    /**
     * Append a new line
     *
     * @return this
     */
    public AnsiFormattedText appendNewLine()
    {
        pieces.add( new AnsiFormattedString( color, attributes, System.lineSeparator() ) );
        return this;
    }

    /**
     * Set formatting to bold. Note that this has no effect on strings already in the text.
     *
     * @return this
     */
    public AnsiFormattedText bold()
    {
        attributes.put( BOLD, true );
        return this;
    }

    public AnsiFormattedText bold( String bold )
    {
        return bold().append( bold ).boldOff();
    }

    /**
     * Set formatting to not bold. Note that this has no effect on strings already in the text.
     *
     * @return this
     */
    public AnsiFormattedText boldOff()
    {
        attributes.put( BOLD, false );
        return this;
    }

    /**
     * Set color to red. Note that this has no effect on strings already in the text.
     *
     * @return this
     */
    public AnsiFormattedText colorRed()
    {
        color = RED;
        return this;
    }

    public AnsiFormattedText colorOrange()
    {
        color = YELLOW;
        return this;
    }

    /**
     * Set color to default. Note that this has no effect on strings already in the text.
     *
     * @return this
     */
    public AnsiFormattedText colorDefault()
    {
        color = DEFAULT_COLOR;
        return this;
    }

    public int textLength()
    {
        return pieces.stream().mapToInt( p -> p.string.length() ).sum();
    }

    /**
     * A formatted string
     */
    private static class AnsiFormattedString
    {
        // can be defined, or undefined. null means undefined.
        final String color;
        // same here, no mapping means undefined
        final Map attributes = new HashMap<>();
        final String string;

        AnsiFormattedString( String color, Map attributes, String s )
        {
            this.color = color;
            this.attributes.putAll( attributes );
            this.string = s;
        }

        @Override
        public String toString()
        {
            return string;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy