package krasa.grepconsole.action; import java.io.*; import java.nio.charset.Charset; import krasa.grepconsole.tail.MyProcessHandler; import krasa.grepconsole.tail.TailContentExecutor; import com.intellij.compiler.server.BuildManager; import com.intellij.execution.impl.ConsoleBuffer; import com.intellij.execution.process.ProcessHandler; import com.intellij.ide.util.BrowseFilesListener; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; /** * @author Vojtech Krasa */ public class OpenFileInConsoleAction extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { final Project project = e.getProject(); final FileChooserDialog fileChooser = FileChooserFactory.getInstance().createFileChooser( BrowseFilesListener.SINGLE_FILE_DESCRIPTOR, project, null); final VirtualFile[] choose = fileChooser.choose(null, project); if (choose.length > 0) { final VirtualFile virtualFile = choose[0]; final String path1 = virtualFile.getPath(); openFileInConsole(project, new File(path1)); } } public void openFileInConsole(final Project project, final File file) { final Process process = new MyProcess(file); final ProcessHandler osProcessHandler = new MyProcessHandler(process, file.getName(), Charset.defaultCharset()) { @Override public boolean isSilentlyDestroyOnClose() { return true; } }; try { osProcessHandler.putUserDataIfAbsent(BuildManager.ALLOW_AUTOMAKE, true); } catch (NoClassDefFoundError e) { //phpstorm does not have it } final TailContentExecutor executor = new TailContentExecutor(project, osProcessHandler); Disposer.register(project, executor); executor.withRerun(new Runnable() { @Override public void run() { osProcessHandler.destroyProcess(); osProcessHandler.waitFor(2000L); openFileInConsole(project, file); } }); executor.forFile(file); executor.withTitle(file.getName()); executor.withStop(new Runnable() { @Override public void run() { osProcessHandler.destroyProcess(); } }, new Computable<Boolean>() { @Override public Boolean compute() { return !osProcessHandler.isProcessTerminated(); } }); executor.run(); } private class MyProcess extends Process { protected volatile boolean running = true; protected FileInputStream inputStream; private MyProcess(final File file) { try { inputStream = new FileInputStream(file); long size = inputStream.getChannel().size(); // close enough, it does not work for binary files very well, but i hope it does at least for text inputStream.getChannel().position(Math.max(size - ConsoleBuffer.getCycleBufferSize(), 0)); } catch (IOException e) { throw new RuntimeException(e); } } @Override public OutputStream getOutputStream() { return new OutputStream() { @Override public void write(int b) throws IOException { } }; } @Override public InputStream getInputStream() { return inputStream; } @Override public InputStream getErrorStream() { return new InputStream() { @Override public int read() throws IOException { return 0; } }; } @Override public int waitFor() throws InterruptedException { while (running) { Thread.sleep(1000); } return 0; } @Override public int exitValue() { return 0; } @Override public void destroy() { try { inputStream.close(); } catch (IOException e) { // who cares } finally { running = false; } } } }