色々な言語を実行可能なEditor

http://d.hatena.ne.jp/Horiuchi_H/20090613/1244875956:昨日のが思いがけずアクセスが増えていたので、自分の環境で動かせるのが perl,ruby,pythonとあったのでその3つを実行できるようにしてみました。

昨日のソースではblogに書きやすく1ファイルに全部書いてましたが、拡張するためにいくつかのクラスに分けました。ソースは http://taoe.jpn.ch:8080/svn/trunk/InteractiveEditor から svnでチェックアウトできます。
MainFrame.java はこんな感じに簡略化されてます。また、このファイルに実行するプロセスのパスが書かれているので、環境に合わせて変更する必要があります*1

package ch.jpn.taoe.interactive.editor;

import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import javax.swing.*;

import ch.jpn.taoe.interactive.editor.event.InteractiveOutputEventListener;
import ch.jpn.taoe.interactive.editor.event.OutputEvent;

public class MainFrame extends JFrame {
	public static class LanguageData {
		public final String tabName;
		public final InteractiveProcess process;

		public LanguageData(String tabName, InteractiveProcess process) {
			this.tabName = tabName;
			this.process = process;
		}
	}


	private final List<LanguageData> languages_ = new ArrayList<LanguageData>();

	private final JTextArea inputArea_ = new JTextArea(5, 20);
	private final JTabbedPane tabPanel_ = new JTabbedPane();
	private final JTextArea[] outputAreas_;

	public MainFrame() {
		super("InteractiveEditor");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		languages_.add(new LanguageData("perl", new InteractiveProcess("C:\\Perl\\bin\\perl", "ipl.pl")));
		languages_.add(new LanguageData("ruby", new InteractiveProcess("C:\\ruby\\bin\\irb.bat", "--simple-prompt")));
		languages_.add(new LanguageData("python", new InteractiveProcess("C:\\Python26\\python", "-i") {
			@Override public boolean isLocalCallback() { return true; }
		}));

		outputAreas_ = new JTextArea[languages_.size()];
		for (int index = 0, size = languages_.size(); index < size; index++) {
			outputAreas_[index] = new JTextArea(3, 20);
			tabPanel_.addTab(languages_.get(index).tabName, new JScrollPane(outputAreas_[index]));
		}
		JSplitPane root = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
				new JScrollPane(inputArea_), tabPanel_);

		add(root);
		this.pack();
	}

	/**
	 * 各外部プロセスを開始します。
	 * @throws IOException
	 */
	public void start() throws IOException {
		for (int index = 0, size = languages_.size(); index < size; index++) {
			final InteractiveProcess process = languages_.get(index).process;

			final JTextArea outputArea = outputAreas_[index];
			process.addInteractiveOutputEventListener(new InteractiveOutputEventListener() {
				@Override
				public void receiveOutput(final OutputEvent e) {
					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							if (isDisplayable()) {
								outputArea.append(e.getOutput());
								//outputArea.append("\r\n");
							}
						};
					});
				}
			});
			process.start();
		}

		inputArea_.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) {
					e.consume();

					String text = inputArea_.getSelectedText();
					if (text == null || text.length() == 0) {
						text = inputArea_.getText();
					}
					try {
						languages_.get(tabPanel_.getSelectedIndex()).process.input(text);
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
			}
		});

		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				for (LanguageData data: languages_) {
					try {
						data.process.stop();
					} catch (IOException ex) {
						ex.printStackTrace();
					}
				}
			}
		});
	}

	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
			ex.printStackTrace();
			return;
		}
		MainFrame f = new MainFrame();
		f.setVisible(true);
		try {
			f.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

他のソースは、上記のリンクから辿ってみてみてください。HTTPでもソースの取得は可能です。

*1:本当は propertiesファイルなどに外出しする必要がありますね^^;