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 020package org.crsh.text.ui; 021 022import groovy.lang.Closure; 023import org.crsh.command.CRaSHCommand; 024import org.crsh.shell.impl.command.spi.CommandInvoker; 025import org.crsh.lang.groovy.command.GroovyScriptCommand; 026import org.crsh.command.InvocationContext; 027import org.crsh.command.ScriptException; 028import org.crsh.text.Chunk; 029import org.crsh.text.LineRenderer; 030import org.crsh.text.RenderPrintWriter; 031import org.crsh.text.Renderer; 032 033import java.io.IOException; 034import java.util.LinkedList; 035import java.util.Map; 036 037public class EvalElement extends Element { 038 039 /** The closure to evaluate. */ 040 Closure closure; 041 042 public LineRenderer renderer() { 043 044 Object owner = closure.getOwner(); 045 046 // 047 final InvocationContext ctx; 048 Object cmd; 049 while (true) { 050 if (owner instanceof CRaSHCommand) { 051 cmd = owner; 052 ctx = ((CRaSHCommand)cmd).peekContext(); 053 break; 054 } else if (owner instanceof GroovyScriptCommand) { 055 cmd = owner; 056 ctx = ((GroovyScriptCommand)cmd).peekContext(); 057 break; 058 } else if (owner instanceof Closure) { 059 owner = ((Closure)owner).getOwner(); 060 } else { 061 throw new UnsupportedOperationException("Cannot resolver owner " + owner + " to command"); 062 } 063 } 064 065 // 066 final LinkedList<LineRenderer> renderers = new LinkedList<LineRenderer>(); 067 068 // 069 final InvocationContext nested = new InvocationContext() { 070 071 /** . */ 072 private LinkedList<Object> buffer = new LinkedList<Object>(); 073 074 /** . */ 075 private Renderer renderable; 076 077 public CommandInvoker<?, ?> resolve(String s) throws ScriptException, IOException { 078 return ctx.resolve(s); 079 } 080 081 public boolean isPiped() { 082 throw new UnsupportedOperationException(); 083 } 084 085 public boolean takeAlternateBuffer() { 086 return false; 087 } 088 089 public boolean releaseAlternateBuffer() { 090 return false; 091 } 092 093 public RenderPrintWriter getWriter() { 094 return ctx.getWriter(); 095 } 096 097 public Map<String, Object> getSession() { 098 return ctx.getSession(); 099 } 100 101 public Map<String, Object> getAttributes() { 102 return ctx.getAttributes(); 103 } 104 105 public int getWidth() { 106 return ctx.getWidth(); 107 } 108 109 public int getHeight() { 110 return ctx.getHeight(); 111 } 112 113 public String getProperty(String propertyName) { 114 return ctx.getProperty(propertyName); 115 } 116 117 public String readLine(String msg, boolean echo) { 118 return null; 119 } 120 121 public Class getConsumedType() { 122 return Object.class; 123 } 124 125 public void write(Chunk chunk) throws IOException { 126 provide(chunk); 127 } 128 129 public void provide(Object element) throws IOException { 130 Renderer current = Renderer.getRenderable(element.getClass()); 131 if (current == null) { 132 current = Renderer.ANY; 133 } 134 if (current != null) { 135 if (renderable != null && !current.equals(renderable)) { 136 flush(); 137 } 138 buffer.addLast(element); 139 renderable = current; 140 } 141 } 142 143 public void flush() throws IOException { 144 // We don't really flush, we just compute renderables from the buffer 145 if (buffer.size() > 0) { 146 LineRenderer i = renderable.renderer(buffer.iterator()); 147 buffer.clear(); 148 renderers.add(i); 149 } 150 } 151 152 public void close() throws IOException { 153 // Nothing to do, except maybe release resources (and also prevent to do any other operation) 154 } 155 }; 156 157 if (cmd instanceof CRaSHCommand) { 158 ((CRaSHCommand)cmd).pushContext(nested); 159 } else { 160 ((GroovyScriptCommand)cmd).pushContext(nested); 161 } 162 try { 163 closure.call(); 164 } 165 finally { 166 if (cmd instanceof CRaSHCommand) { 167 ((CRaSHCommand)cmd).popContext(); 168 } else { 169 ((GroovyScriptCommand)cmd).popContext(); 170 } 171 } 172 173 // Be sure to flush 174 try { 175 nested.flush(); 176 } 177 catch (IOException e) { 178 e.printStackTrace(); 179 } 180 181 // 182 return LineRenderer.vertical(renderers); 183 } 184}