View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.gshell.ansi;
21  
22  /**
23   * Renders ANSI color escape-codes in strings by parsing out some special syntax to pick up the correct fluff to use.
24   *
25   * <p>
26   * The syntax for embedded ANSI codes is:
27   * 
28   * <pre>
29   *  @|<code>(,<code>)*<space><text>|
30   * </pre>
31   *
32   * @version $Rev: 707092 $ $Date: 2008-10-22 16:43:52 +0200 (Wed, 22 Oct 2008) $
33   */
34  public class AnsiRenderer
35  {
36      public static final String BEGIN_TOKEN = "@|";
37  
38      private static final int BEGIN_TOKEN_SIZE = BEGIN_TOKEN.length();
39  
40      public static final String END_TOKEN = "|";
41  
42      private static final int END_TOKEN_SIZE = END_TOKEN.length();
43  
44      public static final String CODE_TEXT_SEPARATOR  = " ";
45  
46      public static final String CODE_LIST_SEPARATOR  = ",";
47  
48      private final AnsiBuffer buff = new AnsiBuffer();
49  
50      public String render(final String input) throws RenderException {
51          assert input != null;
52  
53          // current, prefix and suffix positions
54          int c = 0, p, s;
55  
56          while (c < input.length()) {
57              p = input.indexOf(BEGIN_TOKEN, c);
58              if (p < 0) { break; }
59  
60              s = input.indexOf(END_TOKEN, p + BEGIN_TOKEN_SIZE);
61              if (s < 0) {
62                  throw new RenderException("Missing '" + END_TOKEN + "': " + input);
63              }
64  
65              String expr = input.substring(p + BEGIN_TOKEN_SIZE, s);
66  
67              buff.append(input.substring(c, p));
68  
69              evaluate(expr);
70  
71              c = s + END_TOKEN_SIZE;
72          }
73  
74          buff.append(input.substring(c));
75  
76          return buff.toString();
77      }
78  
79      private void evaluate(final String input) throws RenderException {
80          assert input != null;
81  
82          int i = input.indexOf(CODE_TEXT_SEPARATOR);
83          if (i < 0) {
84              throw new RenderException("Missing ANSI code/text separator '" + CODE_TEXT_SEPARATOR + "': " + input);
85          }
86  
87          String tmp = input.substring(0, i);
88          String[] codes = tmp.split(CODE_LIST_SEPARATOR);
89          String text = input.substring(i + 1, input.length());
90  
91          for (String name : codes) {
92              AnsiCode code = AnsiCode.valueOf(name.toUpperCase());
93              buff.attrib(code);
94          }
95  
96          buff.append(text);
97  
98          buff.attrib(AnsiCode.OFF);
99      }
100 
101     //
102     // RenderException
103     //
104 
105     public static class RenderException
106         extends RuntimeException
107     {
108         public RenderException(final String msg) {
109             super(msg);
110         }
111     }
112 
113     //
114     // Helpers
115     //
116 
117     public static boolean test(final String text) {
118         return text != null && text.indexOf(BEGIN_TOKEN) >= 0;
119     }
120 
121     public static String encode(final Object text, final AnsiCode code) {
122         return new StringBuilder(BEGIN_TOKEN).
123                 append(code.name()).
124                 append(CODE_TEXT_SEPARATOR).
125                 append(text).
126                 append(END_TOKEN).
127                 toString();
128     }
129 }