;; インタラクティブに xyzzy から javascript しようといゆうことで
;; shell-mode を少しいじっただけ
;;
;; (require "js-shell")
;; javascript-mode が必要です。
;;
;; パスを指定する
;; rhino な場合
;; (setq *js-shell-path* (merge-pathnames "rhino1_6R2/js.jar" "C:/usr/bin/"))
;; InteractiveJS な場合 64 行目辺り
;; (setq *js-shell-path* (merge-pathnames "imjs.js" "C:/usr/bin/")) imjsv3.js は手に入らないかも
;; http://d.hatena.ne.jp/nak2k/ 辺り
;;
;; SpiderMonkey の js.exe はわからなかった
;;
;;
;; javascript-mode の keyword と abbrev-table *js-shell-mode-abbrev-table* を追加
;;
;;
(provide "js-shell")
(in-package "editor")
(export '(*js-shell-mode-hook* *js-shell-prompt-regexp* *js-shell-mode-map*
*js-shell-ret* *js-shell-echo* js-shell js-shell-send-input
js-shell-send-interrupt js-shell-alternate-send-input
js-execute-region))
(defvar *js-shell-buffer* "*js-shell*" )
(defvar *js-shell-path* nil)
;;;(setq *js-shell-path* (merge-pathnames "rhino1_6R2/js.jar" "C:/usr/bin/"))
(defvar *js-shell-mode-hook* nil)
(defvar *js-shell-prompt-regexp* "^\[^#$%>?\n]*\[#$%>?] *")
(defvar-local *js-shell-ret* "\n")
(defvar-local *js-shell-echo* nil)
(defvar *js-shell-mode-map* nil)
(unless *js-shell-mode-map*
(setq *js-shell-mode-map* (make-sparse-keymap))
(define-key *js-shell-mode-map* #\RET 'js-shell-send-input)
(define-key *js-shell-mode-map* #\q 'js-shell-exit)
(define-key *js-shell-mode-map* #\C-j 'js-shell-alternate-send-input)
(define-key *js-shell-mode-map* #\C-i 'javascript-completion)
(define-key *js-shell-mode-map* '(#\C-c #\C-c) 'js-shell-send-interrupt))
(defvar *js-shell-mode-abbrev-table* nil)
(unless *js-shell-mode-abbrev-table*
(define-abbrev-table '*js-shell-mode-abbrev-table*))
(defun js-shell-exit()
(interactive)
(when(find-buffer *js-shell-buffer*)
(switch-to-buffer *js-shell-buffer*)
(goto-char(point-max))
(js-shell-send-input)
(insert "quit();")
(js-shell-send-input)
(sit-for 1)
(delete-buffer *js-shell-buffer*)
(delete-window)))
(defun js-shell-mode ()
(setq mode-name "js-shell")
(setq buffer-mode 'js-shell-mode)
(use-keymap *js-shell-mode-map*)
(setq need-not-save t)
(setq auto-save nil)
(setq kept-undo-information nil)
(set-buffer-fold-width 80)
(setq *local-abbrev-table* *js-shell-mode-abbrev-table*)
(cond ((string-matchp *eshell* "command.com$")
(setq *js-shell-ret* "\r" *js-shell-echo* t))
((string-matchp *eshell* "cmd.exe$")
(setq *js-shell-ret* "\n" *js-shell-echo* t))
(t
(setq *js-shell-ret* "\n" *js-shell-echo* nil)))
(run-hooks '*js-shell-mode-hook*))
(defun js-shell ()
(interactive)
(set-buffer (get-buffer-create *js-shell-buffer*))
(let ((proc (buffer-process (selected-buffer))))
(and proc (eq (process-status proc) ':run)
(return-from js-shell t)))
(goto-char (point-max))
(js-shell-mode)
;;imjs(WSH) な人はここをコメントアウトを外して下をコメントアウト
;;(make-process (concat *eshell* " /c cscript " *js-shell-path*) :output (selected-buffer)))
(make-process (concat *eshell* " /c " "java -jar " *js-shell-path*):output (selected-buffer)))
;;;
;;; This code is loosely based on version 0.1 by Yutaka Oiwa .
;;;
(defun js-shell-send-input ()
(interactive)
(let ((process (buffer-process (selected-buffer)))
start end prompt)
(when (and process
(eq (process-status process) :run))
(cond ((>= (point) (marker-point (process-marker process)))
(setq start (marker-point (process-marker process)))
(setq end (progn (goto-eol) (point))))
((save-excursion
(goto-bol)
(looking-at *js-shell-prompt-regexp*))
(setq start (match-end 0))
(setq end (progn (goto-eol) (point)))
(setq prompt (match-string 0)))
(t
(return-from js-shell-send-input nil)))
(let ((cmd (buffer-substring start end)))
(cond ((eobp)
(if *js-shell-echo*
;;(delete-region start end)
(insert "\n")
(insert "\n")))
(t
(goto-char (point-max))
(or (bolp)
(insert "\n"))
(and prompt (insert prompt))
(unless *js-shell-echo*
(insert cmd))))
(set-marker (process-marker process))
(process-send-string process (concatenate 'string cmd *js-shell-ret*)))))
(recenter (round (/ (window-lines) 2))))
(defun js-shell-alternate-send-input ()
(interactive)
(let ((*js-shell-echo* (if (equal *js-shell-echo* "\n")"\r" "\n")))
(declare (special *js-shell-echo*))
(js-shell-send-input)))
(setf (symbol-function 'js-shell-send-interrupt) #'kill-subprocess)
リージョンをshellに投げつけるので編集しながらちょこっとテストする時に使える、*javascript-mode-map* に追加しておくと少し幸せになれるかも
(defvar *js-shell-popup-width* 0)
(defun js-execute-region(beg end)
(interactive "*r")
(let(str b
(send (split-string (buffer-substring beg end) #\LFD))
(curent (selected-buffer))
(buf *js-shell-buffer*))
(setq b (get-buffer-create buf))
(js-shell)
(let ((proc (buffer-process (selected-buffer))))
(loop
(when
(and proc (eq (process-status proc) ':run))
(return)))
(set-buffer b)
(goto-char(point-max))
(let((p1(point)))
(dolist (x send )
(insert (format nil "~A" x))
(funcall 'js-shell-send-input))
(set-buffer curent)
(pop-to-buffer b *js-shell-popup-width*)
(set-buffer b)
(dotimes (i (length send)) (scroll-window 1) (sit-for .05))
(goto-char(point-max))
(recenter (if (zerop *js-shell-popup-width*)
5
(round(/ *js-shell-popup-width* 2))))
(refresh-screen)
(other-window)
))))
(defun js-eval-function(&optional arg)
(interactive "P")
(if arg
(if(find-buffer *js-shell-buffer*)
(switch-to-buffer *js-shell-buffer*)
(js-shell))
(let((p (point)) p1)
(save-excursion
(scan-buffer "^\\(\(?function\\|var\\)"
:regexp t :reverse t :no-dup t)
(setq p1 (point))
(js-execute-region p p1)))
))
window の高さは *js-shell-popup-width*を調整することで幅を変えられる
その都度、一時ファイルに書き出してjsshell.exeを立ち上げて実行しているのであまり効率が良くないような気がするけど一応メモしておく。
function,var,空白行を探して戻り現在行を実行しているので、それなりな所で実行しないとSyntaxErrorを吐きまくります。^^;
(defun spidermonkey-eval-print()
(interactive)
(let*((beg (save-excursion
(goto-eol)
(scan-buffer "^\\($\\|\\(\(?function\\|var\\).+\\({\\|;\\)$\\)"
:regexp t :reverse t :no-dup t)
(point)))
(str (buffer-substring beg (progn(goto-eol)(point))))
(print (split-string str #\LFD))
(file (make-temp-file-name "$js_" "tmp" "~/"));一時ファイルを作る
(cur (selected-buffer))
(buf (get-buffer-create ed::*js-shell-buffer*))
(line (buffer-substring(progn(goto-bol)(point))(progn(goto-eol)(point)))))
(with-open-file(f file :direction :output)
(princ str f)
(dolist(x print)
(format f "~&print(\"~A\")~%"
(substitute-string x "\[\"\']\\(.*?\\)\[\"\']" "\\\\\"\\1\\\\\"")))
(format f "~&print(\"js> \" +~A)~%" line))
(set-buffer buf)
(set-buffer cur)
(pop-to-buffer buf 8);分割
(setq need-not-save t)
(setq auto-save nil)
(setq kept-undo-information nil)
(goto-char (point-max))
(make-process (format nil "js.exe -f \"~A\"" file)
:output (selected-buffer)) ; jsshell.exe?
(dotimes (i (length print)) (sit-for 1)(scroll-window 1) )
(refresh-screen)
(goto-char (point-max))
(recenter (window-height))(refresh-screen)
(other-window)
(start-timer 5 #'(lambda()(delete-file file)) t)
))
ファイルに書き出さなくてもいいバージョン、こっちの方がエラーで出てファイルが残ったりしないのでいいと思う。
(defun spidermonkey-eval-region(from to)
(interactive "*r")
(spidermonkey-eval-print
(buffer-substring from
(if(not(eolp))
(progn(goto-eol)(point))
to))))
(defun spidermonkey-eval-print(&optional string)
(interactive)
(let*((end (save-excursion(goto-eol)(point)))
(beg (save-excursion
;どこまで戻るか
(scan-buffer "^\\($\\|\\(\(?function\\|var\\).+\\({\\|;\\)$\\)"
:regexp t :reverse t :no-dup t)
(point)))
(str (if string string (buffer-substring beg end)))
(print (split-string str #\LFD))
(cur (selected-buffer))
(buf (get-buffer-create ed::*js-shell-buffer*))
(line (buffer-substring(save-excursion(goto-bol)(point)) end))
(proc))
(set-buffer buf)
(setq need-not-save t)
(setq auto-save nil)
(setq kept-undo-information nil)
(goto-char (point-max))
(set-buffer cur)
(pop-to-buffer buf 8)
(setq proc(make-process "js" :output (selected-buffer)))
; 評価しておく
(process-send-string proc (format nil "~A~%" str))
; 一行宛表示
(dolist(x print)
(process-send-string
proc
(format nil "print(\"js> ~A\")~%"
(substitute-string x "\[\"\']\\(.*?\\)\[\"\']"
"\\\\\"\\1\\\\\""))))
; キャレットのある行を評価
(process-send-string
proc
(format nil "~&print(\"js> \" + ~A)~%"
(cond ((string-match ".*//.*" line)
"\"comment line\"")
((string-match "^[ \t]?+?[}].*" line)
(if(string-match "^\\(function\\|var\\) \\(\[^ ]+?\\)\[ (=]" (car print))
(concat "\""(match-string 2)"\"")
"\"not test function\""))
((string-match "var" line)
(substitute-string line "var \\(\[^ ]+?\\) =.*" "\\1"))
(t line))
))
(process-send-string proc (string #\C-z)); process end
(sit-for .5)
(goto-char (point-max))
(recenter (1- (window-height)))
(refresh-screen)
(other-window)
))