/* * Copyright 2015 the original author or authors. * * 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. */ package org.springframework.shell.table; import java.util.HashMap; import java.util.Map; /** * Provides support for different styles of borders, using simple or fancy ascii art. * * @see <a href="https://en.wikipedia.org/wiki/Box-drawing_character">https://en.wikipedia.org/wiki/Box-drawing_character</a> * * @author Eric Bottard */ public enum BorderStyle { /** * A simplistic style, using characters that ought to always be available in all systems (pipe and minus). */ oldschool('|', '-'), /** * A border style that uses dedicated light box drawing characters from the unicode set. */ fancy_light('│', '─'), /** * A border style that uses dedicated fat box drawing characters from the unicode set. */ fancy_heavy('┃', '━'), /** * A border style that uses dedicated double-light box drawing characters from the unicode set. */ fancy_double('║', '═'), /** * A border style that uses space characters, giving some space between columns. */ air(' ', ' '), /** * A border style that uses dedicated double dash light box drawing characters from the unicode set. */ fancy_light_double_dash('╎', '╌'), /** * A border style that uses dedicated double dash light box drawing characters from the unicode set. */ fancy_light_triple_dash('┆', '┄'), /** * A border style that uses dedicated double dash light box drawing characters from the unicode set. */ fancy_light_quadruple_dash('┊', '┈'), /** * A border style that uses dedicated double dash heavy box drawing characters from the unicode set. */ fancy_heavy_double_dash('╏', '╍'), /** * A border style that uses dedicated double dash heavy box drawing characters from the unicode set. */ fancy_heavy_triple_dash('┇', '┅'), /** * A border style that uses dedicated double dash heavy box drawing characters from the unicode set. */ fancy_heavy_quadruple_dash('┋', '┉'), ; private char vertical; private char horizontal; public static final char NONE = '\u0000'; private static Map<Long, Character> CORNERS = new HashMap<Long, Character>(); private static Map<Character, Character> EQUIVALENTS = new HashMap<Character, Character>(); public char verticalGlyph() { return vertical; } public char horizontalGlyph() { return horizontal; } static { registerCorners("─│┌┐└┘├┤┬┴┼"); registerCorners("━┃┏┓┗┛┣┫┳┻╋"); // double dashes registerCorners("╌╎┌┐└┘├┤┬┴┼"); registerCorners("╍╏┏┓┗┛┣┫┳┻╋"); // triple dashes registerCorners("┈┆┌┐└┘├┤┬┴┼"); registerCorners("┅┇┏┓┗┛┣┫┳┻╋"); // quad dashes registerCorners("┈┊┌┐└┘├┤┬┴┼"); registerCorners("┉┋┏┓┗┛┣┫┳┻╋"); // double lines registerCorners("═║╔╗╚╝╠╣╦╩╬"); // oldschool registerCorners("-|+++++++++"); // air style registerCorners(" "); // Register some mixed-style combinations // light + heavy registerCorner('│', '│', '━', NONE, '┥'); registerCorner('│', '│', NONE, '━', '┝'); registerCorner('┃', NONE, '─', '─', '┸'); registerCorner(NONE, '┃', '─', '─', '┰'); // heavy + light registerCorner('┃', '┃', '─', NONE, '┨'); registerCorner('┃', '┃', NONE, '─', '┠'); registerCorner('│', NONE, '━', '━', '┷'); registerCorner(NONE, '│', '━', '━', '┯'); // double + single registerCorner('║', '║', '─', NONE, '╢'); registerCorner('║', '║', NONE, '─', '╟'); registerCorner('│', NONE, '═', '═', '╧'); registerCorner(NONE, '│', '═', '═', '╤'); // single + double registerCorner('│', '│', '═', NONE, '╡'); registerCorner('│', '│', NONE, '═', '╞'); registerCorner('║', NONE, '─', '─', '╨'); registerCorner(NONE, '║', '─', '─', '╥'); // heavy + light, 90° registerCorner('┃', '│', '━', '─', '╃'); registerCorner('│', '┃', '─', '━', '╆'); registerCorner('┃', '│', '─', '━', '╄'); registerCorner('│', '┃', '━', '─', '╅'); // light crossing (heavy or double) registerCorner('│', '│', '━', '━', '┿'); registerCorner('│', '│', '═', '═', '╪'); registerCorner('┃', '┃', '─', '─', '╂'); registerCorner('║', '║', '─', '─', '╫'); // Dashed variants crossing others behave like regular corners registerSameCorners(fancy_light_double_dash, fancy_light); registerSameCorners(fancy_light_triple_dash, fancy_light); registerSameCorners(fancy_light_quadruple_dash, fancy_light); registerSameCorners(fancy_heavy_double_dash, fancy_heavy); registerSameCorners(fancy_heavy_triple_dash, fancy_heavy); registerSameCorners(fancy_heavy_quadruple_dash, fancy_heavy); // Air-style glyphs are easy to combine with others. Register some combinations registerMixedWithAirCombinations(oldschool.vertical, oldschool.horizontal); registerMixedWithAirCombinations(fancy_light.vertical, fancy_light.horizontal); registerMixedWithAirCombinations(fancy_double.vertical, fancy_double.horizontal); registerMixedWithAirCombinations(fancy_heavy.vertical, fancy_heavy.horizontal); registerMixedWithAirCombinations(fancy_light_double_dash.vertical, fancy_light_double_dash.horizontal); registerMixedWithAirCombinations(fancy_light_triple_dash.vertical, fancy_light_triple_dash.horizontal); registerMixedWithAirCombinations(fancy_light_quadruple_dash.vertical, fancy_light_quadruple_dash.horizontal); registerMixedWithAirCombinations(fancy_heavy_double_dash.vertical, fancy_heavy_double_dash.horizontal); registerMixedWithAirCombinations(fancy_heavy_triple_dash.vertical, fancy_heavy_triple_dash.horizontal); registerMixedWithAirCombinations(fancy_heavy_quadruple_dash.vertical, fancy_heavy_quadruple_dash.horizontal); } /** * Register the fact that for corner purposes, style1 behaves like style2. */ private static void registerSameCorners(BorderStyle style1, BorderStyle style2) { EQUIVALENTS.put(style1.horizontal, style2.horizontal); EQUIVALENTS.put(style1.vertical, style2.vertical); } private static void registerMixedWithAirCombinations(char vertical, char horizontal) { registerCorner(vertical, vertical, ' ', NONE, vertical); registerCorner(vertical, vertical, NONE, ' ', vertical); registerCorner(vertical, vertical, ' ', ' ', vertical); registerCorner(' ', NONE, horizontal, horizontal, horizontal); registerCorner(NONE, ' ', horizontal, horizontal, horizontal); registerCorner(' ', ' ', horizontal, horizontal, horizontal); } /** * Register corner glyphs for a given set, not taking care of mixed style intersections. */ private static void registerCorners(String list) { char horizontal = list.charAt(0); char vertical = list.charAt(1); registerCorner(NONE, vertical, NONE, horizontal, list.charAt(2)); registerCorner(NONE, vertical, horizontal, NONE, list.charAt(3)); registerCorner(vertical, NONE, NONE, horizontal, list.charAt(4)); registerCorner(vertical, NONE, horizontal, NONE, list.charAt(5)); registerCorner(vertical, vertical, NONE, horizontal, list.charAt(6)); registerCorner(vertical, vertical, horizontal, NONE, list.charAt(7)); registerCorner(NONE, vertical, horizontal, horizontal, list.charAt(8)); registerCorner(vertical, NONE, horizontal, horizontal, list.charAt(9)); registerCorner(vertical, vertical, horizontal, horizontal, list.charAt(10)); } private static void registerCorner(char above, char below, char left, char right, char corner) { long key = key(above, below, left, right); CORNERS.put(key, corner); } public static char intersection(char above, char below, char left, char right) { above = EQUIVALENTS.get(above) != null ? EQUIVALENTS.get(above) : above; below = EQUIVALENTS.get(below) != null ? EQUIVALENTS.get(below) : below; left = EQUIVALENTS.get(left) != null ? EQUIVALENTS.get(left) : left; right = EQUIVALENTS.get(right) != null ? EQUIVALENTS.get(right) : right; Character character = CORNERS.get(key(above, below, left, right)); return character != null ? character : NONE; } private static long key(char above, char below, char left, char right) { return (long) above << 48 | (long) below << 32 | (long) left << 16 | (long) right; } BorderStyle(char vertical, char horizontal) { this.vertical = vertical; this.horizontal = horizontal; } }