(require "ni/setup")
(ni-autoload)
(require "xml/xhtml")
(require "xml/xslt")
(require "my-buffer-bar-context-menu")

(load-library "winkey2")

(load-library "php-mode")
(pushnew '("\\.php$" . php-mode) *auto-mode-alist*)

(load-library "bash-mode")
(pushnew '("\\.sh$" . bash-mode) *auto-mode-alist*)

(load-library "py-mode")
(push '("\\.py$" . py-mode) *auto-mode-alist*)
(setq *py-indent-tabs-mode* t)

(load-library "ruby-mode")
(load-library "ruby-doc")
(push '("\\.rb$" . ruby-mode) *auto-mode-alist*)
(setq editor::*ruby-indent-column* nil)
(setq editor::*ruby-tab-always-indent* t)


; とにかく TAB にしろ
(setq c-indent-level 4)
(setq c-continued-statement-offset 4)
(setq c-argdecl-indent 4)
(setq c-brace-offset 0)
(setq c-brace-imaginary-offset 0)
(setq c-label-offset 0)
(setq c-comment-indent 4)
(setq *c-indent-tabs-mode* t)
(setq *c-tab-always-indent* t)

(setq editor::*php-indent-tabs-mode* t)

(setq *css-indent-level* 4)
(setq *css-continued-statement-offset* 4)
(setq *css-brace-offset* 0)
(setq *css-brace-imaginary-offset* 0)
(setq *css-argdecl-indent* 0)
(setq *css-label-offset* 0)


(setq c++-indent-level 4)
(setq c++-continued-statement-offset 4)
(setq c++-argdecl-indent 4)
(setq c++-brace-offset 0)
(setq c++-brace-imaginary-offset 0)
(setq c++-label-offset 0)
(setq c++-comment-indent 4)
(setq *c++-indent-tabs-mode* t)

(setq java-indent-level 4)
(setq java-continued-statement-offset 4)
(setq java-argdecl-indent 4)
(setq java-brace-offset 0)
(setq java-brace-imaginary-offset 0)
(setq java-label-offset 0)
(setq java-comment-indent 4)
(setq editor::*java-indent-tabs-mode* t)

(setq *jscript-indent-tabs-mode* t)

(setq *lisp-body-indention* 4)
(setq *lisp-body-indent* 4)
(setq *lisp-indent-tabs-mode* t)

(setq *xml-indent-column* 4)
(setq *xml-indent-tabs-mode* t)

; for Esperanto
(global-set-key #\M-C '(lambda () (interactive) (insert (code-char 582))))
(global-set-key #\M-c '(lambda () (interactive) (insert (code-char 614))))
(global-set-key #\M-G '(lambda () (interactive) (insert (code-char 600))))
(global-set-key #\M-g '(lambda () (interactive) (insert (code-char 632))))
(global-set-key #\M-H '(lambda () (interactive) (insert (code-char 550))))
(global-set-key #\M-h '(lambda () (interactive) (insert (code-char 566))))
(global-set-key #\M-J '(lambda () (interactive) (insert (code-char 556))))
(global-set-key #\M-j '(lambda () (interactive) (insert (code-char 572))))
(global-set-key #\M-S '(lambda () (interactive) (insert (code-char 606))))
(global-set-key #\M-s '(lambda () (interactive) (insert (code-char 638))))
(global-set-key #\M-U '(lambda () (interactive) (insert (code-char 605))))
(global-set-key #\M-u '(lambda () (interactive) (insert (code-char 637))))

(global-set-key #\M-\` '(lambda () (interactive) (insert "&#8216;")))
(global-set-key #\M-\' '(lambda () (interactive) (insert "&#8217;")))
(global-set-key #\M-2 '(lambda () (interactive) (insert "&#8220;")))
(global-set-key #\M-\" '(lambda () (interactive) (insert "&#8221;")))

(global-set-key #\C-> '(lambda () (interactive) (insert "&gt;")))
(global-set-key #\C-< '(lambda () (interactive) (insert "&lt;")))
(global-set-key #\C-& '(lambda () (interactive) (insert "&amp;")))


;特殊バッファを削除してウィンドウを１つにする
(defun cleanup-window()
	(interactive)
	(let ((bufl (buffer-list)) buf name)
		(loop
			(setq buf (pop bufl))
			(if (null buf) (return nil))
			(setq name (buffer-name buf))
			(if (member-if
				 #'(lambda (str) (string= name str))
				 '("*grep*" "*Help*" "*Completion*" "*Shell output*"
				   "*Calendar*" "*PickupPatternShow*" "*dictionary*"
				   "*Buffer List*" "*XML Command error*" "*FTP LOG*"
				   "*buf2html: HTML*" "buf2html: CSS*" "*output*"
				   "*lftp" "*Command Output*"
				   ))
					(delete-buffer buf)))
		(delete-other-windows)))
(global-set-key #\S-F11 'cleanup-window)


; memo
; lambda () は匿名関数。クオートは本当はいらんらしいけど付けとく。
; 動かすやつは (interactive) が必要。
; let で局所変数作成。let 内が変数スコープ。
; setq = setf. setq の方が古風。
; in-pakage 使ったら (in-package "user") で戻すの忘れずに。


; Unix-Timestamp
(global-set-key #\C-2
				#'(lambda ()
					  (interactive)
					  (with-output-to-selected-buffer
						  (format t "~d" (- (get-universal-time) (encode-universal-time 0 0 9 1 1 1970))))))

; xml datetime
(global-set-key #\C-1
				#'(lambda ()
					  (interactive)
					  (let (date)
						  (setq date (format-date-string "%Y-%m-%dT%H:%M:%S%Z"))
						  (insert (concat (substring date 0 -2) ":" (substring date -2)))))) ;%Z => "+0900" -> "+09:00"

;対応する括弧を強調
;http://plaza28.mbn.or.jp/~kitaj/xyzzy/
(require "paren")
(turn-on-global-paren)

; auto-space-mode（=全角の半角の間にスペース）
;(require "auto-space")


;とりあえずデフォルトも設定しとく
(global-set-key #\C-h 'delete-backward-char-or-selection)
; xml-mode とかで TAB が解体されるのがウザいので再定義
(setf (symbol-function 'backward-delete-char-untabify-or-selection)
	  #'delete-backward-char-or-selection)
;セレクションインデント。S-TAB を F20 に設定 C-TAB を F21 に設定。
(set-extended-key-translate-table exkey-S-tab #\F20)
(set-extended-key-translate-table exkey-C-tab #\F21)
(global-set-key  #\F21 'shift-selection)
(global-set-key  #\F20 'unshift-selection)



;http://www.uranus.dti.ne.jp/~shiro-/soft/xyzzy/index.html
;;補完候補リストをチップヘルプにする
;;(setq *print-completion-list-hook*
;;	  '(lambda (list prefix &optional string)
;;		(popup-string (format nil "~D items:\n~{\n~A~}" (length list) list) (point))))

;;補完候補リストをポップアップにする。
; そのまま選択して入力可能。
(require "dabbrev")
(global-set-key #\C-@ 'dabbrev-popup)
(setq *popup-completion-list-default* :always)
(setq *minibuffer-popup-completion-list* :always)


;バッファ移動をツールバー表示順にする
(setq *next-buffer-in-tab-order* t)
(global-set-key #\C-\F12 'next-buffer)
(global-set-key #\C-\F11 'previous-buffer)

;ごみ箱を使って削除
(setq *filer-use-recycle-bin* t)

;キーワードディレクトリの設定
(setq *keyword-load-path* '("~/xyzzy/keyword/"))
(setq *template-insert-directory* "~/xyzzy/templates/")

(load-library "info-modoki")
(define-key ed::*lisp-mode-map*  #\F1 'lisp-info-F1)
(define-key ed::*lisp-interaction-mode-map* #\F1 'lisp-info-F1)

;; なんでも一発インデント
; 構造変えたときなど、これないとアレ。
(defun indent-current-buffer ()
	(interactive)
	(indent-region (point-min) (point-max))
	(message "indent buffer"))
(global-set-key #\C-F8 'indent-current-buffer)
(global-set-key #\C-F7 'indent-region)
; モードを設定しなおす。xml-mode CDATA 区域のアレ用。
(global-set-key #\C-F5 #'(lambda ()
							 (interactive)
							 (command-execute buffer-mode)))

;http://hie.3.pro.tok2.com/xyzzy/note/major_mode.html
;;; css-enhance - 拡張版CSSモード。
; インデントをちゃんとしてくれる。つか必須。
; library
(load-library "css-mode")
; indent (お好みでどうぞ)
(defvar *css-indent-level* 4)
(defvar *css-continued-statement-offset* 4)
(defvar *css-brace-offset* -4)
(defvar *css-brace-imaginary-offset* 0)
(defvar *css-argdecl-indent* 0)
(defvar *css-label-offset* 0)
; keymap (お好みでどうぞ)
(define-key *css-mode-map* #\{ 'c-electric-insert)
(define-key *css-mode-map* #\: 'c-electric-insert)
(define-key *css-mode-map* #\} 'c-electric-close)
(define-key *css-mode-map* #\C-h 'backward-delete-char-untabify-or-selection)
(define-key *css-mode-map* #\TAB 'c-indent-line)
(define-key *css-mode-map* #\C-M-q 'indent-sexp)
(define-key *css-mode-map* #\RET 'c-newline-and-indent)
(define-key *css-mode-map* #\C-. 'ed::css-completion)
; function for hook
(defun css-enhance ()
	;; indent command
	(make-local-variable 'mode-specific-indent-command)
	(make-local-variable 'c-comment-indent-variable)
	(setq c-comment-indent-variable 'c-comment-indent)
	(setq mode-specific-indent-command 'c-indent-line)
	; indent
	(make-local-variable 'c-indent-level)
	(make-local-variable 'c-continued-statement-offset)
	(make-local-variable 'c-brace-offset)
	(make-local-variable 'c-brace-imaginary-offset)
	(make-local-variable 'c-argdecl-indent)
	(make-local-variable 'c-label-offset)
	(setq c-indent-level *css-indent-level*)
	(setq c-continued-statement-offset *css-continued-statement-offset*)
	(setq c-brace-offset *css-brace-offset*)
	(setq c-brace-imaginary-offset *css-brace-imaginary-offset*)
	(setq c-argdecl-indent *css-argdecl-indent*)
	(setq c-label-offset *css-label-offset*)
	; comment
	(setq comment-indent-function 'c-comment-indent)
	(setq comment-start "/*" comment-end "*/")
	(setq comment-start-skip "/\\(\\*+\\|/\\)[ \t]*"))
; hook
(add-hook '*css-mode-hook* 'css-enhance)


;; lisp-mode 色付け (ただし lisp に keyword なんてものないので、それっぽいのを色づけ。)
(in-package "editor")
(defvar *lisp-keyword-hash-table* nil)
(defun use-lisp-keyword ()
	"キーワード色付け"
	(if (null *lisp-keyword-hash-table*)
			(setq *lisp-keyword-hash-table*
				  (load-keyword-file "lisp")))
	(when *lisp-keyword-hash-table*
		(make-local-variable 'keyword-hash-table)
		(setq keyword-hash-table *lisp-keyword-hash-table*)))
(add-hook '*lisp-mode-hook*
		  #'(lambda ()
				(use-lisp-keyword)
				(define-key *lisp-mode-map* #\C-. 'lisp-complete-symbol)))
(add-hook '*lisp-interaction-mode-hook*
		  #'(lambda ()
				(use-lisp-keyword)
				(define-key *lisp-interaction-mode-map* #\C-. 'lisp-complete-symbol)))
(in-package "user")


; http://members4.tsukaeru.net/skry/xyzzy.html
; ----- 選択範囲の行処理
(defun skr-treat-selection-lines(func)
	(interactive)
	(save-excursion
		(let ((count 0))
			(when (get-selection-type)
				(save-restriction
					(narrow-to-region (selection-mark) (selection-point))
					(goto-char (point-min))
					(setq count (count-matches "\n"))
					(widen)))
			(goto-bol)
			;(setq count (+ count 1)); (改行数+1)行
			(dotimes (i count)
				(funcall func)
				(forward-line 1)))
		(when (get-selection-type) ;選択範囲があれば維持
			(goto-char (selection-mark))
			(start-selection 2 t)
			(goto-char (selection-point)))))
; モードごとの行コメント設定
;(setq line-comment-string '((lisp-mode . ";")
;							(ruby-mode . "#")
;							(perl-mode . "#")
;							(c-mode . "//")
;							(c++-mode . "//")))
; 行頭コメントをトグル
(defun toggle-line-comment()
	(interactive)
	(skr-treat-selection-lines ;(キャレットは行頭)
	 '(lambda ()
	   (let ((comment-str (cdr (assoc buffer-mode line-comment-string))))
		   (if (looking-at "\\^\\[ \t\\]") ;その行が空白文字で始まっていれば
				   (skip-chars-forward " \t")) ;空白文字以外の文字までスキップ
		   (unless (looking-at (concat "\\(\n\\|" comment-str "\\)"));   次が改行かコメントでなければ
			   (insert comment-str))
		   (if (looking-at comment-str)
				   (delete-region (match-beginning 0) (match-end 0)))))))
(global-set-key #\C-\M-c 'toggle-line-comment)

; S-F1 でマクロ記録・終了
; S-F2 でマクロ実行
(defun startend-kbd-macro()
	(interactive)
	(if (kbd-macro-saving-p)
			(progn
				(message "定義終了")
				(end-kbd-macro))
		(progn
			(message "定義開始")
			(start-kbd-macro))))
(global-set-key #\S-F1 'startend-kbd-macro)
(global-set-key #\S-F2 'call-last-kbd-macro)


(require "ldoc")
(turn-on-ldoc)

(global-set-key #\C-M-f 'list-function)
