001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.text.ui; 021 022 import groovy.lang.Closure; 023 import org.crsh.groovy.GroovyCommand; 024 import org.crsh.shell.impl.command.AbstractInvocationContext; 025 import org.crsh.shell.impl.command.spi.CommandException; 026 import org.crsh.text.Screenable; 027 import org.crsh.shell.impl.command.spi.CommandInvoker; 028 import org.crsh.lang.impl.groovy.command.GroovyScriptCommand; 029 import org.crsh.command.InvocationContext; 030 import org.crsh.text.CLS; 031 import org.crsh.text.LineRenderer; 032 import org.crsh.text.RenderPrintWriter; 033 import org.crsh.text.Renderer; 034 import org.crsh.text.Style; 035 036 import java.io.IOException; 037 import java.util.LinkedList; 038 import java.util.Map; 039 040 public class EvalElement extends Element { 041 042 /** The closure to evaluate. */ 043 Closure closure; 044 045 public LineRenderer renderer() { 046 047 Object owner = closure.getOwner(); 048 049 // 050 final InvocationContext ctx; 051 Object cmd; 052 while (true) { 053 if (owner instanceof GroovyCommand) { 054 cmd = owner; 055 ctx = ((GroovyCommand)cmd).peekContext(); 056 break; 057 } else if (owner instanceof GroovyScriptCommand) { 058 cmd = owner; 059 ctx = ((GroovyScriptCommand)cmd).peekContext(); 060 break; 061 } else if (owner instanceof Closure) { 062 owner = ((Closure)owner).getOwner(); 063 } else { 064 throw new UnsupportedOperationException("Cannot resolver owner " + owner + " to command"); 065 } 066 } 067 068 // 069 final LinkedList<LineRenderer> renderers = new LinkedList<LineRenderer>(); 070 071 // 072 final InvocationContext nested = new AbstractInvocationContext() { 073 074 /** . */ 075 private LinkedList<Object> buffer = new LinkedList<Object>(); 076 077 /** . */ 078 private Renderer renderable; 079 080 public CommandInvoker<?, ?> resolve(String s) throws CommandException { 081 return ctx.resolve(s); 082 } 083 084 public boolean takeAlternateBuffer() { 085 return false; 086 } 087 088 public boolean releaseAlternateBuffer() { 089 return false; 090 } 091 092 public RenderPrintWriter getWriter() { 093 return ctx.getWriter(); 094 } 095 096 public Map<String, Object> getSession() { 097 return ctx.getSession(); 098 } 099 100 public Map<String, Object> getAttributes() { 101 return ctx.getAttributes(); 102 } 103 104 public int getWidth() { 105 return ctx.getWidth(); 106 } 107 108 public int getHeight() { 109 return ctx.getHeight(); 110 } 111 112 public String getProperty(String propertyName) { 113 return ctx.getProperty(propertyName); 114 } 115 116 public String readLine(String msg, boolean echo) { 117 return null; 118 } 119 120 public Class getConsumedType() { 121 return Object.class; 122 } 123 124 public Screenable append(CharSequence s) throws IOException { 125 provide(s); 126 return this; 127 } 128 129 @Override 130 public Appendable append(char c) throws IOException { 131 return append(Character.toString(c)); 132 } 133 134 @Override 135 public Appendable append(CharSequence csq, int start, int end) throws IOException { 136 return append(csq.subSequence(start, end)); 137 } 138 139 public Screenable append(Style style) throws IOException { 140 provide(style); 141 return this; 142 } 143 144 public Screenable cls() throws IOException { 145 provide(CLS.INSTANCE); 146 return this; 147 } 148 149 public void provide(Object element) throws IOException { 150 Renderer current = Renderer.getRenderable(element.getClass()); 151 if (current == null) { 152 current = Renderer.ANY; 153 } 154 if (current != null) { 155 if (renderable != null && !current.equals(renderable)) { 156 flush(); 157 } 158 buffer.addLast(element); 159 renderable = current; 160 } 161 } 162 163 public void flush() throws IOException { 164 // We don't really flush, we just compute renderables from the buffer 165 if (buffer.size() > 0) { 166 LineRenderer i = renderable.renderer(buffer.iterator()); 167 buffer.clear(); 168 renderers.add(i); 169 } 170 } 171 172 public void close() throws IOException { 173 // Nothing to do, except maybe release resources (and also prevent to do any other operation) 174 } 175 }; 176 177 if (cmd instanceof GroovyCommand) { 178 ((GroovyCommand)cmd).pushContext(nested); 179 } else { 180 ((GroovyScriptCommand)cmd).pushContext(nested); 181 } 182 try { 183 closure.call(); 184 } 185 finally { 186 if (cmd instanceof GroovyCommand) { 187 ((GroovyCommand)cmd).popContext(); 188 } else { 189 ((GroovyScriptCommand)cmd).popContext(); 190 } 191 } 192 193 // Be sure to flush 194 try { 195 nested.flush(); 196 } 197 catch (Exception e) { 198 e.printStackTrace(); 199 } 200 201 // 202 return LineRenderer.vertical(renderers); 203 } 204 }