;;; -*- Mode: Lisp; Package: EDITOR; Last updated: "2008/01/08 00:52:00" -*-
;;;
;;; This file is not part of xyzzy.
;;;
;;;   ruby-mode-plus.l - ruby-mode の改変を試みる
;;;

(require "ruby")
(require "ruby-misc")

(in-package "editor")

(export '(*ruby-plus-exerb-prog*
	  *ruby-plus-mkexy-prog*
	  *ruby-plus-backup-dir*
	  *ruby-plus-html-help-path*
	  ruby-plus-show-html-help
	  ))

;;; ──────────────────────────────────── ;;;
;;;  ■ 標準関数の上書き
;;;     ・半角スペースを含むパスに対応
;;; ──────────────────────────────────── ;;;

(defun ruby-run-script ()
  "スクリプトを走らせる"
  (interactive)
  (let (command
	(bufname "*Run Script*")
	(file (get-buffer-file-name)))
    (when file
      (when (setq command (read-string "Check: "
				       :default (concat *ruby-prog* " \"" file "\"")))
	(ruby-error-popup-buffer bufname)
	(execute-shell-command command nil bufname)))))

(defun ruby-syntax-check ()
  "スクリプトのエラーチェック"
  (interactive)
  (let (command
	(bufname "*Syntax Check*")
	(file (get-buffer-file-name)))
    (when file
      (when (setq command (read-string "Check: "
				       :default (concat *ruby-prog* " -wc \"" file "\"")))
	(ruby-error-popup-buffer bufname)
	(execute-shell-command command nil bufname)))))


;;; ──────────────────────────────────── ;;;
;;;  ■ 標準関数の上書き
;;;  ・ インデントの改良
;;;       TT プログラマ記:
;;;         http://childs.squares.net/d/index.cgi?p=%282007.02.08%29
;;; ──────────────────────────────────── ;;;

(setq *ruby-block-beg-re*
      "\\(class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do\\)\\>\\($\\|[^_]\\)")

(setq *ruby-block-end-re* "end\\>\\($\\|[^_]\\)")

(defun calc-ruby-indent ()
  "インデントする数を数える"
  (let ((column 0) (curp (point)))
    (save-excursion
      ;前の行を調べる
      (when (ruby-previous-line)
	(goto-bol)
	(skip-chars-forward " \t")
	; インデント数
	(setq column (current-column))
	;(message-box (format nil "column1: ~D" column))
	(save-restriction
	  (narrow-to-region (progn (goto-eol) (point))
			    (progn (goto-bol) (point)))
	  (skip-chars-forward " \t")
	  ; 開きものがあればインデント数を増やす
	  (cond
	   ((looking-at *ruby-block-beg-re*)
	    (setq column (+ column *ruby-indent-column*)))
	   ((looking-at *ruby-block-mid-re*)
	    (setq column (+ column *ruby-indent-column*)))
	   (;(scan-buffer "\\<do\\>" :regexp t)
	    ;;↓↓ここを変更↓↓
	    (scan-buffer "\\<do\\>\\($\\|[^_]\\)" :regexp t)
	    ;;↑↑↑↑↑↑↑↑↑
	    (setq column (+ column *ruby-indent-column*)))
	   ((and (scan-buffer "\{" :regexp t) (not (scan-buffer "\}" :regexp t)))
	    (setq column (+ column *ruby-indent-column*)))
	   ((and (scan-buffer "\(" :regexp t) (not (scan-buffer "\)" :regexp t)))
	    (setq column (+ column *ruby-indent-column*)))
	  )
	)))
    ;(message-box (format nil "column2: ~D" column))
    ; 現在の行を調べる
    (save-excursion
      (save-restriction
	(narrow-to-region (progn (goto-eol) (point))
			  (progn (goto-bol) (point)))
	(goto-bol)
	(skip-chars-forward " \t")
	; 閉じものがあればインデント数を減らす
	(cond
	 ((looking-at "^=\\(begin\\|end\\)")
	  (setq column 0))
	 ((looking-at "\}")
	  (setq column (- column *ruby-indent-column*)))
	 ((looking-at "\)")
	  (setq column (- column *ruby-indent-column*)))
	 ((looking-at *ruby-block-end-re*)
	  (setq column (- column *ruby-indent-column*)))
	 ((looking-at *ruby-block-mid-re*)
	  (setq column (- column *ruby-indent-column*)))
	)))
    column
  ))


;;; ──────────────────────────────────── ;;;
;;;  ■ HTML Help
;;; ──────────────────────────────────── ;;;

(defvar *ruby-plus-html-help-path*
  (merge-pathnames "rubymanjp.chm" (merge-pathnames "etc" (si:system-root))))

(defun ruby-plus-show-html-help ()
  (interactive)
  (html-help *ruby-plus-html-help-path* (get-winhelp-topic)))


;;; ──────────────────────────────────── ;;;
;;;  ■ セレクションをまとめてインデント
;;; ──────────────────────────────────── ;;;

(defun ruby-plus-indent-selection ()
  (interactive)
  (when (and (get-selection-type)
	     (< (get-selection-type) 3))
    (indent-region (selection-mark) (selection-point))))


;;; ──────────────────────────────────── ;;;
;;;  ■ Exerb
;;; ──────────────────────────────────── ;;;

(defvar *ruby-plus-mkexy-prog* "mkexy")
(defvar *ruby-plus-exerb-prog* "exerb")
(defvar *ruby-plus-backup-dir* "backup")

(defun ruby-plus-mkexy ()
  "レシピファイルを生成"
  (interactive)
  (let* (command
	 (bufname "*Run mkexy*")
	 (f (get-buffer-file-name))
	 (path (directory-namestring f))
	 (src  (file-namestring f))
	 (fn   (pathname-name f))
	 (exy  (concat fn ".exy"))
	 (exyfile (merge-pathnames exy path))
	 (bakpath (merge-pathnames *ruby-plus-backup-dir* path))
	 )
    (when f
      ;; 更新確認 or バックアップ
      (when (file-exist-p exyfile)
	(if (file-exist-p bakpath)
	    (let ((date (format-date-string "%Y%m%d%H%M%S" (get-universal-time))))
	      (rename-file exyfile (merge-pathnames (concat exy "." date) bakpath)))
	  (unless (case (message-box "レシピファイルを更新しますか?" nil
				     '(:yes-no :question :button2))
		    (:yes t))
	    (return-from ruby-plus-mkexy nil))))
      ;; コマンド生成 & mkexy 実行
      (when (setq command (read-string "Check: " :default (concat *ruby-plus-mkexy-prog* " " src)))
	(long-operation
	  (multiple-value-bind (cmdline dir)
	      (shell-command-line command path)
	    (call-process cmdline
			  :exec-directory dir
			  :show :minimize
			  :wait t))
	  (find-file exyfile))))))
(define-key *ruby-mode-map* '(#\C-c #\m) 'ruby-plus-mkexy)

(defun ruby-plus-exerb ()
  "実行ファイルを作成"
  (interactive)
  (let* (command
	 (bufname "*Run Exerb*")
	 (f (get-buffer-file-name))
	 (path (directory-namestring f))
	 (fn   (pathname-name f))
	 (exy  (concat fn ".exy"))
	 (exyfile (merge-pathnames exy path))
	 (exe  (concat fn ".exe"))
	 (exefile (merge-pathnames exe path))
	 (bakpath (merge-pathnames *ruby-plus-backup-dir* path))
	 )
    (when f
      ;; レシピファイルの存在確認
      (unless (file-exist-p exyfile)
	(message "レシピファイルがありません")
	(return-from ruby-plus-exerb nil))
      ;; 更新確認 or バックアップ
      (when (file-exist-p exefile)
	(if (file-exist-p bakpath)
	    (let ((date (format-date-string "%Y%m%d%H%M%S" (get-universal-time))))
	      (rename-file exefile (merge-pathnames (concat exe "." date) bakpath)))
	  (unless (case (message-box "実行ファイルを更新しますか?" nil
				     '(:yes-no :question :button2))
		    (:yes t))
	    (return-from ruby-plus-exerb nil))))
      ;; コマンド生成 & exerb 実行
      (when (setq command (read-string "Check: " :default (concat *ruby-plus-exerb-prog* " " exy)))
	(long-operation
	  (multiple-value-bind (cmdline dir)
	      (shell-command-line command path)
	    (call-process cmdline
			  :exec-directory dir
			  :show :minimize
			  :wait t))))
      (message "実行ファイルを作成しますた."))))
(define-key *ruby-mode-map* '(#\C-c #\c) 'ruby-plus-exerb)

;;; ruby-mode-plus.l ends here.