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.processor.jline; 021 022 import org.crsh.shell.ShellProcessContext; 023 import org.crsh.shell.ShellResponse; 024 import org.crsh.text.Chunk; 025 import org.crsh.text.Style; 026 import org.crsh.text.Text; 027 028 import java.io.IOException; 029 import java.util.concurrent.CountDownLatch; 030 import java.util.concurrent.atomic.AtomicReference; 031 032 class JLineProcessContext implements ShellProcessContext { 033 034 /** . */ 035 private static final Character NO_ECHO = (char)0; 036 037 /** . */ 038 final JLineProcessor processor; 039 040 /** . */ 041 final CountDownLatch latch = new CountDownLatch(1); 042 043 /** . */ 044 final AtomicReference<ShellResponse> resp = new AtomicReference<ShellResponse>(); 045 046 public JLineProcessContext(JLineProcessor processor) { 047 this.processor = processor; 048 } 049 050 public boolean takeAlternateBuffer() { 051 if (!processor.useAlternate) { 052 processor.useAlternate = true; 053 054 // To get those codes I captured the output of telnet running top 055 // on OSX: 056 // 1/ sudo /usr/libexec/telnetd -debug #run telnet 057 // 2/ telnet localhost >output.txt 058 // 3/ type username + enter 059 // 4/ type password + enter 060 // 5/ type top + enter 061 // 6/ ctrl-c 062 // 7/ type exit + enter 063 064 // Save screen and erase 065 processor.writer.print("\033[?47h"); // Switches to the alternate screen 066 // writer.print("\033[1;43r"); 067 // processor.writer.print("\033[m"); // Reset to normal (Sets SGR parameters : 0 m == m) 068 // writer.print("\033[4l"); 069 // writer.print("\033[?1h"); 070 // writer.print("\033[="); 071 // processor.writer.print("\033[H"); // Move the cursor to home 072 // processor.writer.print("\033[2J"); // Clear screen 073 // processor.writer.flush(); 074 } 075 return true; 076 } 077 078 public boolean releaseAlternateBuffer() { 079 if (processor.useAlternate) { 080 processor.useAlternate = false; 081 processor.writer.print("\033[?47l"); // Switches back to the normal screen 082 } 083 return true; 084 } 085 086 public int getWidth() { 087 return processor.reader.getTerminal().getWidth(); 088 } 089 090 public int getHeight() { 091 return processor.reader.getTerminal().getHeight(); 092 } 093 094 public String getProperty(String name) { 095 return null; 096 } 097 098 public String readLine(String msg, boolean echo) { 099 try { 100 if (echo) { 101 return processor.reader.readLine(msg); 102 } else { 103 return processor.reader.readLine(msg, NO_ECHO); 104 } 105 } 106 catch (IOException e) { 107 return null; 108 } 109 } 110 111 public Class<Chunk> getConsumedType() { 112 return Chunk.class; 113 } 114 115 public void provide(Chunk element) throws IOException { 116 if (element instanceof Text) { 117 Text textChunk = (Text)element; 118 processor.writer.append(textChunk.getText()); 119 } else if (element instanceof Style) { 120 try { 121 ((Style)element).writeAnsiTo(processor.writer); 122 } 123 catch (IOException ignore) { 124 } 125 } else { 126 127 128 // Clear screen 129 processor.writer.print("\033[2J"); 130 processor.writer.print("\033[1;1H"); 131 } 132 } 133 134 public void flush() { 135 processor.writer.flush(); 136 } 137 138 public void end(ShellResponse response) { 139 try { 140 resp.set(response); 141 latch.countDown(); 142 } 143 finally { 144 // Release screen if it wasn't done 145 releaseAlternateBuffer(); 146 } 147 } 148 }