diff options
Diffstat (limited to 'jni/ruby/misc')
-rw-r--r-- | jni/ruby/misc/README | 12 | ||||
-rw-r--r-- | jni/ruby/misc/inf-ruby.el | 418 | ||||
-rw-r--r-- | jni/ruby/misc/rb_optparse.bash | 20 | ||||
-rwxr-xr-x | jni/ruby/misc/rb_optparse.zsh | 38 | ||||
-rw-r--r-- | jni/ruby/misc/rdoc-mode.el | 166 | ||||
-rw-r--r-- | jni/ruby/misc/ruby-additional.el | 126 | ||||
-rw-r--r-- | jni/ruby/misc/ruby-electric.el | 475 | ||||
-rw-r--r-- | jni/ruby/misc/ruby-mode.el | 1584 | ||||
-rw-r--r-- | jni/ruby/misc/ruby-style.el | 79 | ||||
-rw-r--r-- | jni/ruby/misc/rubydb2x.el | 104 | ||||
-rw-r--r-- | jni/ruby/misc/rubydb3x.el | 115 |
11 files changed, 3137 insertions, 0 deletions
diff --git a/jni/ruby/misc/README b/jni/ruby/misc/README new file mode 100644 index 0000000..08a9010 --- /dev/null +++ b/jni/ruby/misc/README @@ -0,0 +1,12 @@ +README this file +inf-ruby.el program to run ruby under emacs +rb_optparse.bash bash completion script +rb_optparse.zsh zsh completion script +rdoc-mode.el RDoc mode for emacs +ruby-mode.el ruby mode for emacs +ruby-style.el Ruby's C/C++ mode style for emacs +rubydb2x.el ruby debugger support for emacs 19.2x or before +rubydb3x.el ruby debugger support for emacs 19.3x or later +ruby-electric.el emacs minor mode providing electric commands + +Check out https://github.com/ruby-debug/ also. diff --git a/jni/ruby/misc/inf-ruby.el b/jni/ruby/misc/inf-ruby.el new file mode 100644 index 0000000..6e977f1 --- /dev/null +++ b/jni/ruby/misc/inf-ruby.el @@ -0,0 +1,418 @@ +;;; -*-Emacs-Lisp-*- +;;; +;;; $Id: inf-ruby.el 42804 2013-09-03 09:29:22Z knu $ +;;; $Author: knu $ +;;; +;;; Inferior Ruby Mode - ruby process in a buffer. +;;; adapted from cmuscheme.el +;;; +;;; Usage: +;;; +;;; (0) check ruby-program-name variable that can run your environment. +;;; +;;; (1) modify .emacs to use ruby-mode +;;; for example : +;;; +;;; (autoload 'ruby-mode "ruby-mode" +;;; "Mode for editing ruby source files" t) +;;; (setq auto-mode-alist +;;; (append '(("\\.rb$" . ruby-mode)) auto-mode-alist)) +;;; (setq interpreter-mode-alist (append '(("ruby" . ruby-mode)) +;;; interpreter-mode-alist)) +;;; +;;; (2) set to load inf-ruby and set inf-ruby key definition in ruby-mode. +;;; +;;; (autoload 'run-ruby "inf-ruby" +;;; "Run an inferior Ruby process") +;;; (autoload 'inf-ruby-keys "inf-ruby" +;;; "Set local key defs for inf-ruby in ruby-mode") +;;; (add-hook 'ruby-mode-hook +;;; '(lambda () +;;; (inf-ruby-keys) +;;; )) +;;; +;;; HISTORY +;;; senda - 8 Apr 1998: Created. +;;; $Log$ +;;; Revision 1.7 2004/07/27 08:11:36 matz +;;; * eval.c (rb_eval): copy on write for argument local variable +;;; assignment. +;;; +;;; * eval.c (assign): ditto. +;;; +;;; * eval.c (rb_call0): update ruby_frame->argv with the default +;;; value used for the optional arguments. +;;; +;;; * object.c (Init_Object): "===" calls rb_obj_equal() directly. +;;; [ruby-list:39937] +;;; +;;; Revision 1.6 2002/09/07 14:35:46 nobu +;;; * misc/inf-ruby.el (inferior-ruby-error-regexp-alist): regexp +;;; alist for error message from ruby. +;;; +;;; * misc/inf-ruby.el (inferior-ruby-mode): fixed for Emacs. +;;; +;;; * misc/inf-ruby.el (ruby-send-region): compilation-parse-errors +;;; doesn't parse first line, so insert separators before each +;;; evaluations. +;;; +;;; Revision 1.5 2002/08/19 10:05:47 nobu +;;; * misc/inf-ruby.el (inf-ruby-keys): ruby-send-definition +;;; conflicted with ruby-insert-end. +;;; +;;; * misc/inf-ruby.el (inferior-ruby-mode): compilation-minor-mode. +;;; +;;; * misc/inf-ruby.el (ruby-send-region): send as here document to +;;; adjust source file/line. [ruby-talk:47113], [ruby-dev:17965] +;;; +;;; * misc/inf-ruby.el (ruby-send-terminator): added to make unique +;;; terminator. +;;; +;;; Revision 1.4 2002/01/29 07:16:09 matz +;;; * file.c (rb_stat_rdev_major): added. [new] +;;; +;;; * file.c (rb_stat_rdev_minor): added. [new] +;;; +;;; * file.c (rb_stat_inspect): print mode in octal. +;;; +;;; Revision 1.3 1999/12/01 09:24:18 matz +;;; 19991201 +;;; +;;; Revision 1.2 1999/08/13 05:45:18 matz +;;; 1.4.0 +;;; +;;; Revision 1.1.1.1.2.1 1999/07/15 07:59:59 matz +;;; 990715 +;;; +;;; Revision 1.1.1.1 1999/01/20 04:59:36 matz +;;; ruby 1.3 cycle +;;; +;;; Revision 1.1.2.1 1998/12/16 07:30:36 matz +;;; first public release of 1.1d (pre1.2) series +;;; +;;; Revision 1.4 1998/05/20 02:45:58 senda +;;; default program to irb +;;; +;;; Revision 1.3 1998/04/10 04:11:30 senda +;;; modification by Matsumoto san (1.1b9_09) +;;; remove-in-string defined +;;; global variable : +;;; inferior-ruby-first-prompt-pattern +;;; inferior-ruby-prompt-pattern +;;; defined +;;; +;;; Revision 1.2 1998/04/09 07:53:42 senda +;;; remove M-C-x in inferior-ruby-mode +;;; +;;; Revision 1.1 1998/04/09 07:28:36 senda +;;; Initial revision +;;; +;;; + +(require 'comint) +(require 'compile) +(require 'ruby-mode) + +;; +;; you may change these variables +;; +;(defvar ruby-program-name "rbc --noreadline" +; "*Program invoked by the run-ruby command") +; +;(defvar inferior-ruby-first-prompt-pattern "^rbc0> *" +; "first prompt regex pattern of ruby interpreter.") +; +;(defvar inferior-ruby-prompt-pattern "^\\(rbc.[>*\"'] *\\)+" +; "prompt regex pattern of ruby interpreter.") + +;;;; for irb +(defvar ruby-program-name "irb --inf-ruby-mode" + "*Program invoked by the run-ruby command") + +(defvar inferior-ruby-first-prompt-pattern "^irb(.*)[0-9:]+0> *" + "first prompt regex pattern of ruby interpreter.") + +(defvar inferior-ruby-prompt-pattern "^\\(irb(.*)[0-9:]+[>*\"'] *\\)+" + "prompt regex pattern of ruby interpreter.") + +;; +;; mode variables +;; +(defvar inferior-ruby-mode-hook nil + "*Hook for customising inferior-ruby mode.") +(defvar inferior-ruby-mode-map nil + "*Mode map for inferior-ruby-mode") + +(defconst inferior-ruby-error-regexp-alist + '(("SyntaxError: compile error\n^\\([^\(].*\\):\\([1-9][0-9]*\\):" 1 2) + ("^\tfrom \\([^\(].*\\):\\([1-9][0-9]*\\)\\(:in `.*'\\)?$" 1 2))) + +(cond ((not inferior-ruby-mode-map) + (setq inferior-ruby-mode-map + (copy-keymap comint-mode-map)) +; (define-key inferior-ruby-mode-map "\M-\C-x" ;gnu convention +; 'ruby-send-definition) +; (define-key inferior-ruby-mode-map "\C-x\C-e" 'ruby-send-last-sexp) + (define-key inferior-ruby-mode-map "\C-c\C-l" 'ruby-load-file) +)) + +;;;###autoload +(defun inf-ruby-keys () + "Set local key defs for inf-ruby in ruby-mode" + (define-key ruby-mode-map "\M-\C-x" 'ruby-send-definition) +; (define-key ruby-mode-map "\C-x\C-e" 'ruby-send-last-sexp) + (define-key ruby-mode-map "\C-c\C-b" 'ruby-send-block) + (define-key ruby-mode-map "\C-c\M-b" 'ruby-send-block-and-go) + (define-key ruby-mode-map "\C-c\C-x" 'ruby-send-definition) + (define-key ruby-mode-map "\C-c\M-x" 'ruby-send-definition-and-go) + (define-key ruby-mode-map "\C-c\C-r" 'ruby-send-region) + (define-key ruby-mode-map "\C-c\M-r" 'ruby-send-region-and-go) + (define-key ruby-mode-map "\C-c\C-z" 'switch-to-ruby) + (define-key ruby-mode-map "\C-c\C-l" 'ruby-load-file) + (define-key ruby-mode-map "\C-c\C-s" 'run-ruby) +) + +(defvar ruby-buffer nil "current ruby (actually irb) process buffer.") + +(defun inferior-ruby-mode () + "Major mode for interacting with an inferior ruby (irb) process. + +The following commands are available: +\\{inferior-ruby-mode-map} + +A ruby process can be fired up with M-x run-ruby. + +Customisation: Entry to this mode runs the hooks on comint-mode-hook and +inferior-ruby-mode-hook (in that order). + +You can send text to the inferior ruby process from other buffers containing +Ruby source. + switch-to-ruby switches the current buffer to the ruby process buffer. + ruby-send-definition sends the current definition to the ruby process. + ruby-send-region sends the current region to the ruby process. + + ruby-send-definition-and-go, ruby-send-region-and-go, + switch to the ruby process buffer after sending their text. +For information on running multiple processes in multiple buffers, see +documentation for variable ruby-buffer. + +Commands: +Return after the end of the process' output sends the text from the + end of process to point. +Return before the end of the process' output copies the sexp ending at point + to the end of the process' output, and sends it. +Delete converts tabs to spaces as it moves back. +Tab indents for ruby; with argument, shifts rest + of expression rigidly with the current line. +C-M-q does Tab on each line starting within following expression. +Paragraphs are separated only by blank lines. # start comments. +If you accidentally suspend your process, use \\[comint-continue-subjob] +to continue it." + (interactive) + (comint-mode) + ;; Customise in inferior-ruby-mode-hook + ;(setq comint-prompt-regexp "^[^>\n]*>+ *") + (setq comint-prompt-regexp inferior-ruby-prompt-pattern) + ;;(scheme-mode-variables) + (ruby-mode-variables) + (setq major-mode 'inferior-ruby-mode) + (setq mode-name "Inferior Ruby") + (setq mode-line-process '(":%s")) + (use-local-map inferior-ruby-mode-map) + (setq comint-input-filter (function ruby-input-filter)) + (setq comint-get-old-input (function ruby-get-old-input)) + (make-local-variable 'compilation-error-regexp-alist) + (setq compilation-error-regexp-alist inferior-ruby-error-regexp-alist) + (compilation-shell-minor-mode t) + (run-hooks 'inferior-ruby-mode-hook)) + +(defvar inferior-ruby-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'" + "*Input matching this regexp are not saved on the history list. +Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.") + +(defun ruby-input-filter (str) + "Don't save anything matching inferior-ruby-filter-regexp" + (not (string-match inferior-ruby-filter-regexp str))) + +;; adapted from replace-in-string in XEmacs (subr.el) +(defun remove-in-string (str regexp) + "Remove all matches in STR for REGEXP and returns the new string." + (let ((rtn-str "") (start 0) match prev-start) + (while (setq match (string-match regexp str start)) + (setq prev-start start + start (match-end 0) + rtn-str (concat rtn-str (substring str prev-start match)))) + (concat rtn-str (substring str start)))) + +(defun ruby-get-old-input () + "Snarf the sexp ending at point" + (save-excursion + (let ((end (point))) + (re-search-backward inferior-ruby-first-prompt-pattern) + (remove-in-string (buffer-substring (point) end) + inferior-ruby-prompt-pattern) + ))) + +(defun ruby-args-to-list (string) + (let ((where (string-match "[ \t]" string))) + (cond ((null where) (list string)) + ((not (= where 0)) + (cons (substring string 0 where) + (ruby-args-to-list (substring string (+ 1 where) + (length string))))) + (t (let ((pos (string-match "[^ \t]" string))) + (if (null pos) + nil + (ruby-args-to-list (substring string pos + (length string))))))))) + +;;;###autoload +(defun run-ruby (cmd) + "Run an inferior Ruby process, input and output via buffer *ruby*. +If there is a process already running in `*ruby*', switch to that buffer. +With argument, allows you to edit the command line (default is value +of `ruby-program-name'). Runs the hooks `inferior-ruby-mode-hook' +\(after the `comint-mode-hook' is run). +\(Type \\[describe-mode] in the process buffer for a list of commands.)" + + (interactive (list (if current-prefix-arg + (read-string "Run Ruby: " ruby-program-name) + ruby-program-name))) + (if (not (comint-check-proc "*ruby*")) + (let ((cmdlist (ruby-args-to-list cmd))) + (set-buffer (apply 'make-comint "ruby" (car cmdlist) + nil (cdr cmdlist))) + (inferior-ruby-mode))) + (setq ruby-program-name cmd) + (setq ruby-buffer "*ruby*") + (pop-to-buffer "*ruby*")) + +(defconst ruby-send-terminator "--inf-ruby-%x-%d-%d-%d--" + "Template for irb here document terminator. +Must not contain ruby meta characters.") + +(defconst ruby-eval-separator "") + +(defun ruby-send-region (start end) + "Send the current region to the inferior Ruby process." + (interactive "r") + (let (term (file (buffer-file-name)) line) + (save-excursion + (save-restriction + (widen) + (goto-char start) + (setq line (+ start (forward-line (- start)) 1)) + (goto-char start) + (while (progn + (setq term (apply 'format ruby-send-terminator (random) (current-time))) + (re-search-forward (concat "^" (regexp-quote term) "$") end t))))) + ;; compilation-parse-errors parses from second line. + (save-excursion + (let ((m (process-mark (ruby-proc)))) + (set-buffer (marker-buffer m)) + (goto-char m) + (insert ruby-eval-separator "\n") + (set-marker m (point)))) + (comint-send-string (ruby-proc) (format "eval <<'%s', nil, %S, %d\n" term file line)) + (comint-send-region (ruby-proc) start end) + (comint-send-string (ruby-proc) (concat "\n" term "\n")))) + +(defun ruby-send-definition () + "Send the current definition to the inferior Ruby process." + (interactive) + (save-excursion + (ruby-end-of-defun) + (let ((end (point))) + (ruby-beginning-of-defun) + (ruby-send-region (point) end)))) + +;(defun ruby-send-last-sexp () +; "Send the previous sexp to the inferior Ruby process." +; (interactive) +; (ruby-send-region (save-excursion (backward-sexp) (point)) (point))) + +(defun ruby-send-block () + "Send the current block to the inferior Ruby process." + (interactive) + (save-excursion + (ruby-end-of-block) + (end-of-line) + (let ((end (point))) + (ruby-beginning-of-block) + (ruby-send-region (point) end)))) + +(defun switch-to-ruby (eob-p) + "Switch to the ruby process buffer. +With argument, positions cursor at end of buffer." + (interactive "P") + (if (get-buffer ruby-buffer) + (pop-to-buffer ruby-buffer) + (error "No current process buffer. See variable ruby-buffer.")) + (cond (eob-p + (push-mark) + (goto-char (point-max))))) + +(defun ruby-send-region-and-go (start end) + "Send the current region to the inferior Ruby process. +Then switch to the process buffer." + (interactive "r") + (ruby-send-region start end) + (switch-to-ruby t)) + +(defun ruby-send-definition-and-go () + "Send the current definition to the inferior Ruby. +Then switch to the process buffer." + (interactive) + (ruby-send-definition) + (switch-to-ruby t)) + +(defun ruby-send-block-and-go () + "Send the current block to the inferior Ruby. +Then switch to the process buffer." + (interactive) + (ruby-send-block) + (switch-to-ruby t)) + +(defvar ruby-source-modes '(ruby-mode) + "*Used to determine if a buffer contains Ruby source code. +If it's loaded into a buffer that is in one of these major modes, it's +considered a ruby source file by ruby-load-file. +Used by these commands to determine defaults.") + +(defvar ruby-prev-l/c-dir/file nil + "Caches the last (directory . file) pair. +Caches the last pair used in the last ruby-load-file command. +Used for determining the default in the +next one.") + +(defun ruby-load-file (file-name) + "Load a Ruby file into the inferior Ruby process." + (interactive (comint-get-source "Load Ruby file: " ruby-prev-l/c-dir/file + ruby-source-modes t)) ; T because LOAD + ; needs an exact name + (comint-check-source file-name) ; Check to see if buffer needs saved. + (setq ruby-prev-l/c-dir/file (cons (file-name-directory file-name) + (file-name-nondirectory file-name))) + (comint-send-string (ruby-proc) (concat "(load \"" + file-name + "\"\)\n"))) + +(defun ruby-proc () + "Returns the current ruby process. See variable ruby-buffer." + (let ((proc (get-buffer-process (if (eq major-mode 'inferior-ruby-mode) + (current-buffer) + ruby-buffer)))) + (or proc + (error "No current process. See variable ruby-buffer")))) + +;;; Do the user's customisation... + +(defvar inf-ruby-load-hook nil + "This hook is run when inf-ruby is loaded in. +This is a good place to put keybindings.") + +(run-hooks 'inf-ruby-load-hook) + +(provide 'inf-ruby) + +;;; inf-ruby.el ends here diff --git a/jni/ruby/misc/rb_optparse.bash b/jni/ruby/misc/rb_optparse.bash new file mode 100644 index 0000000..8a59ec2 --- /dev/null +++ b/jni/ruby/misc/rb_optparse.bash @@ -0,0 +1,20 @@ +#! /bin/bash +# Completion for bash: +# +# (1) install this file, +# +# (2) load the script, and +# . ~/.profile.d/rb_optparse.bash +# +# (3) define completions in your .bashrc, +# rb_optparse command_using_optparse_1 +# rb_optparse command_using_optparse_2 + +_rb_optparse() { + COMPREPLY=($("${COMP_WORDS[0]}" "--*-completion-bash=${COMP_WORDS[COMP_CWORD]}")) + return 0 +} + +rb_optparse () { + [ $# = 0 ] || complete -o default -F _rb_optparse "$@" +} diff --git a/jni/ruby/misc/rb_optparse.zsh b/jni/ruby/misc/rb_optparse.zsh new file mode 100755 index 0000000..d53170c --- /dev/null +++ b/jni/ruby/misc/rb_optparse.zsh @@ -0,0 +1,38 @@ +#!/bin/zsh +# Completion for zsh: +# (based on <http://d.hatena.ne.jp/rubikitch/20071002/zshcomplete>) +# +# (1) install this file. +# mkdir -p ~/.zsh.d +# cp rb_optparse.zsh ~/.zsh.d/rb_optparse.zsh +# +# (2) load the script, and add a directory to fpath before compinit. +# echo '. ~/.zsh.d/rb_optparse.zsh' >> ~/.zshrc +# echo 'fpath=(~/.zsh.d/Completion $fpath)' >> ~/.zshrc +# echo 'autoload -U compinit; compinit' >> ~/.zshrc +# +# (3) restart zsh. +# +# (4) geneate completion files once. +# generate-complete-function/ruby/optparse COMMAND1 +# generate-complete-function/ruby/optparse COMMAND2 +# + +generate-complete-function/ruby/optparse () +{ + local cmpl="_${1:t}" + mkdir -p "${ZSH_COMPLETION_DIR-$HOME/.zsh.d/Completion}" + $1 "--*-completion-zsh=${1:t}" >! "${ZSH_COMPLETION_DIR-$HOME/.zsh.d/Completion}/$cmpl" + if [[ $(type -w "$cmpl") == "${cmpl}: function" ]]; then + unfunction "$cmpl" + autoload -U "$cmpl" + else + compinit "$cmpl" + fi +} + +compdef _command generate-complete-function/ruby/optparse + +for cmd in "$@"; do + generate-complete-function/ruby/optparse "$cmd" +done diff --git a/jni/ruby/misc/rdoc-mode.el b/jni/ruby/misc/rdoc-mode.el new file mode 100644 index 0000000..c26c2ee --- /dev/null +++ b/jni/ruby/misc/rdoc-mode.el @@ -0,0 +1,166 @@ +;; +;; rdoc-mode.el +;; Major mode for RDoc editing +;; + +;; Created: Fri Sep 18 09:04:49 JST 2009 + +;; License: Ruby's + +(require 'derived) + +;;;###autoload +(define-derived-mode rdoc-mode text-mode "RDoc" + "Major mode for RD editing. +\\{rdoc-mode-map}" + (make-local-variable 'paragraph-separate) + (setq paragraph-separate "^\\(=+\\|\\*+\\)[ \t\v\f]*\\|^\\s *$") + (make-local-variable 'paragraph-start) + (setq paragraph-start paragraph-separate) + (make-local-variable 'require-final-newline) + (setq require-final-newline t) + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '((rdoc-font-lock-keywords) t nil)) + (make-local-variable 'font-lock-keywords) + (setq font-lock-keywords rdoc-font-lock-keywords) + (make-local-variable 'outline-regexp) + (setq outline-regexp "^\\(=+\\)[ \t\v\f]*") + (outline-minor-mode t) + (setq show-trailing-whitespace t) + (rdoc-setup-keys) + (setq indent-tabs-mode nil) + (run-hooks 'rdoc-mode-hook) + ) + +(defun rdoc-fill-paragraph (&optional justify region) + "Fills paragraph, except for cited region" + (interactive (progn + (barf-if-buffer-read-only) + (list (if current-prefix-arg 'full)))) + (save-excursion + (beginning-of-line) + (save-restriction + (let ((pos (point)) beg end indent hanging) + (cond + ((looking-at "^ +\\(\\*\\s *\\)") + (setq indent (- (match-end 0) (match-beginning 0)) + hanging (- (match-end 1) (match-beginning 1)))) + ((looking-at "^ +") + (setq indent (- (match-end 0) (match-beginning 0))) + (when (and (re-search-backward "^[^ ]\\|^\\( *\\(\\* *\\)\\)" nil t) + (match-beginning 1) + (= indent (- (match-end 1) (match-beginning 1)))) + (setq hanging (- (match-end 2) (match-beginning 2))) + (setq beg (match-beginning 1)))) + ((setq beg t))) + (when beg + (when indent + (goto-char pos) + (while (progn (beginning-of-line 2) + (and (looking-at "^\\( +\\)\\S ") + (= indent (- (match-end 1) (match-beginning 1)))))) + (setq end (point)) + (when (and beg (not region)) + (setq region (list beg end)) + (narrow-to-region beg end) + )) + (goto-char pos) + (fill-paragraph justify region) + (when (and indent + (or (goto-char beg) t) + (or (beginning-of-line 2) t) + (looking-at "^\\( +\\)") + (= (- indent hanging) (- (match-end 0) (match-beginning 0)))) + (insert-char ?\s hanging) + (beginning-of-line) + (narrow-to-region (point) end) + (fill-paragraph justify (list (point) end)))))))) + +(defun rdoc-setup-keys () + (interactive) + (define-key rdoc-mode-map "\M-q" 'rdoc-fill-paragraph) + ) + +(defvar rdoc-heading1-face 'font-lock-keywordoc-face) +(defvar rdoc-heading2-face 'font-lock-type-face) +(defvar rdoc-heading3-face 'font-lock-variable-name-face) +(defvar rdoc-heading4-face 'font-lock-comment-face) +(defvar rdoc-bold-face 'font-lock-function-name-face) +(defvar rdoc-emphasis-face 'font-lock-function-name-face) +(defvar rdoc-code-face 'font-lock-keyword-face) +(defvar rdoc-description-face 'font-lock-constant-face) + +(defvar rdoc-font-lock-keywords + (list + (list "^=([^=\r\n].*)?$" + 0 rdoc-heading1-face) + (list "^==([^=\r\n].*)?$" + 0 rdoc-heading2-face) + (list "^===([^=\r\n].*)?$" + 0 rdoc-heading3-face) + (list "^====+.*$" + 0 rdoc-heading4-face) + (list "\\(^\\|[ \t\v\f]\\)\\(\\*\\(\\sw\\|[-_:]\\)+\\*\\)\\($\\|[ \t\v\f]\\)" + 2 rdoc-bold-face) ; *bold* + (list "\\(^\\|[ \t\v\f]\\)\\(_\\(\\sw\\|[-_:]\\)+_\\)\\($\\|[ \t\v\f]\\)" + 2 rdoc-emphasis-face) ; _emphasis_ + (list "\\(^\\|[ \t\v\f]\\)\\(\\+\\(\\sw\\|[-_:]\\)+\\+\\)\\($\\|[ \t\v\f]\\)" + 2 rdoc-code-face) ; +code+ + (list "<em>[^<>]*</em>" 0 rdoc-emphasis-face) + (list "<i>[^<>]*</i>" 0 rdoc-emphasis-face) + (list "<b>[^<>]*</b>" 0 rdoc-bold-face) + (list "<tt>[^<>]*</tt>" 0 rdoc-code-face) + (list "<code>[^<>]*</code>" 0 rdoc-code-face) + (list "^\\([-*]\\|[0-9]+\\.\\|[A-Za-z]\\.\\)\\s " + 1 rdoc-description-face) ; bullet | numbered | alphabetically numbered + (list "^\\[[^\]]*\\]\\|\\S .*::\\)\\([ \t\v\f]\\|$\\)" + 1 rdoc-description-face) ; labeled | node + ;(list "^[ \t\v\f]+\\(.*\\)" 1 rdoc-verbatim-face) + )) + +(defun rdoc-imenu-create-index () + (let ((root '(nil . nil)) + cur-alist + (cur-level 0) + (pattern (concat outline-regexp "\\(.*?\\)[ \t\v\f]*$")) + (empty-heading "-") + (self-heading ".") + pos level heading alist) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward pattern (point-max) t) + (setq heading (match-string-no-properties 2) + level (min 6 (length (match-string-no-properties 1))) + pos (match-beginning 1)) + (if (= (length heading) 0) + (setq heading empty-heading)) + (setq alist (list (cons heading pos))) + (cond + ((= cur-level level) ; new sibling + (setcdr cur-alist alist) + (setq cur-alist alist)) + ((< cur-level level) ; first child + (dotimes (i (- level cur-level 1)) + (setq alist (list (cons empty-heading alist)))) + (if cur-alist + (let* ((parent (car cur-alist)) + (self-pos (cdr parent))) + (setcdr parent (cons (cons self-heading self-pos) alist))) + (setcdr root alist)) ; primogenitor + (setq cur-alist alist + cur-level level)) + (t ; new sibling of an ancestor + (let ((sibling-alist (last (cdr root)))) + (dotimes (i (1- level)) + (setq sibling-alist (last (cdar sibling-alist)))) + (setcdr sibling-alist alist) + (setq cur-alist alist + cur-level level)))))) + (cdr root))) + +(defun rdoc-set-imenu-create-index-function () + (setq imenu-create-index-function 'rdoc-imenu-create-index)) + +(add-hook 'rdoc-mode-hook 'rdoc-set-imenu-create-index-function) + +(provide 'rdoc-mode) diff --git a/jni/ruby/misc/ruby-additional.el b/jni/ruby/misc/ruby-additional.el new file mode 100644 index 0000000..b77b526 --- /dev/null +++ b/jni/ruby/misc/ruby-additional.el @@ -0,0 +1,126 @@ +;;; ruby-additional.el --- ruby-mode extensions yet to be merged into Emacs + +;; Authors: Yukihiro Matsumoto, Nobuyoshi Nakada, Akinori MUSHA +;; URL: http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/misc/ +;; Created: 3 Sep 2012 +;; Package-Requires: ((emacs "24.3") (ruby-mode "1.2")) +;; Keywords: ruby, languages + +;;; Commentary: +;; +;; This package contains ruby-mode extensions yet to be merged into +;; the latest released version of Emacs distribution. For older +;; versions of Emacs, use ruby-mode.el bundled with CRuby. + +;;; Code: + +(eval-when-compile + (require 'ruby-mode)) + +(eval-after-load 'ruby-mode + '(progn + (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end) + + (defun ruby-insert-end () + (interactive) + (if (eq (char-syntax (preceding-char)) ?w) + (insert " ")) + (insert "end") + (save-excursion + (if (eq (char-syntax (following-char)) ?w) + (insert " ")) + (ruby-indent-line t) + (end-of-line))) + + (defconst ruby-default-encoding-map + '((us-ascii . nil) ;; Do not put coding: us-ascii + (utf-8 . nil) ;; Do not put coding: utf-8 + (shift-jis . cp932) ;; Emacs charset name of Shift_JIS + (shift_jis . cp932) ;; MIME charset name of Shift_JIS + (japanese-cp932 . cp932)) ;; Emacs charset name of CP932 + ) + + (custom-set-default 'ruby-encoding-map ruby-default-encoding-map) + + (defcustom ruby-encoding-map ruby-default-encoding-map + "Alist to map encoding name from Emacs to Ruby. +Associating an encoding name with nil means it needs not be +explicitly declared in magic comment." + :type '(repeat (cons (symbol :tag "From") (symbol :tag "To"))) + :group 'ruby) + + (defun ruby-mode-set-encoding () + "Insert or update a magic comment header with the proper encoding. +`ruby-encoding-map' is looked up to convert an encoding name from +Emacs to Ruby." + (let* ((nonascii + (save-excursion + (widen) + (goto-char (point-min)) + (re-search-forward "[^\0-\177]" nil t))) + (coding-system + (or coding-system-for-write + buffer-file-coding-system)) + (coding-system + (and coding-system + (coding-system-change-eol-conversion coding-system nil))) + (coding-system + (and coding-system + (or + (coding-system-get coding-system :mime-charset) + (let ((coding-type (coding-system-get coding-system :coding-type))) + (cond ((eq coding-type 'undecided) + (if nonascii + (or (and (coding-system-get coding-system :prefer-utf-8) + 'utf-8) + (coding-system-get default-buffer-file-coding-system :coding-type) + 'ascii-8bit))) + ((memq coding-type '(utf-8 shift-jis)) + coding-type) + (t coding-system)))))) + (coding-system + (or coding-system + 'us-ascii)) + (coding-system + (let ((cons (assq coding-system ruby-encoding-map))) + (if cons (cdr cons) coding-system))) + (coding-system + (and coding-system + (symbol-name coding-system)))) + (if coding-system + (save-excursion + (widen) + (goto-char (point-min)) + (if (looking-at "^#!") (beginning-of-line 2)) + (cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)\\s *\\(;\\|-\*-\\)") + (unless (string= (match-string 2) coding-system) + (goto-char (match-beginning 2)) + (delete-region (point) (match-end 2)) + (and (looking-at "-\*-") + (let ((n (skip-chars-backward " "))) + (cond ((= n 0) (insert " ") (backward-char)) + ((= n -1) (insert " ")) + ((forward-char))))) + (insert coding-system))) + ((looking-at "\\s *#.*coding\\s *[:=]")) + (t (when ruby-insert-encoding-magic-comment + (insert "# -*- coding: " coding-system " -*-\n")))))))) + + (define-key ruby-mode-map "\C-cU" 'ruby-encode-unicode) + + (defun ruby-encode-unicode (beg end) + "Convert non-ascii string in the given region to \\u{} form." + (interactive "r") + (setq end (set-marker (make-marker) end)) + (goto-char beg) + (while (and (< (point) end) + (re-search-forward "\\Ca+" end t)) + (let ((u (mapconcat (lambda (c) (format "%x" c)) (match-string-no-properties 0) " "))) + (delete-region (match-beginning 0) (match-end 0)) + (insert "\\u{" u "}")) + )) + )) + +(provide 'ruby-additional) + +;;; ruby-additional.el ends here diff --git a/jni/ruby/misc/ruby-electric.el b/jni/ruby/misc/ruby-electric.el new file mode 100644 index 0000000..b8897e7 --- /dev/null +++ b/jni/ruby/misc/ruby-electric.el @@ -0,0 +1,475 @@ +;;; ruby-electric.el --- Minor mode for electrically editing ruby code +;; +;; Authors: Dee Zsombor <dee dot zsombor at gmail dot com> +;; Yukihiro Matsumoto +;; Nobuyoshi Nakada +;; Akinori MUSHA <knu@iDaemons.org> +;; Jakub Kuźma <qoobaa@gmail.com> +;; Maintainer: Akinori MUSHA <knu@iDaemons.org> +;; Created: 6 Mar 2005 +;; URL: https://github.com/knu/ruby-electric.el +;; Keywords: languages ruby +;; License: The same license terms as Ruby +;; Version: 2.1.1 + +;;; Commentary: +;; +;; `ruby-electric-mode' accelerates code writing in ruby by making +;; some keys "electric" and automatically supplying with closing +;; parentheses and "end" as appropriate. +;; +;; This work was originally inspired by a code snippet posted by +;; [Frederick Ros](https://github.com/sleeper). +;; +;; Add the following line to enable ruby-electric-mode under +;; ruby-mode. +;; +;; (eval-after-load "ruby-mode" +;; '(add-hook 'ruby-mode-hook 'ruby-electric-mode)) +;; +;; Type M-x customize-group ruby-electric for configuration. + +;;; Code: + +(require 'ruby-mode) + +(defgroup ruby-electric nil + "Minor mode providing electric editing commands for ruby files" + :group 'ruby) + +(defconst ruby-electric-expandable-bar-re + "\\s-\\(do\\|{\\)\\s-*|") + +(defconst ruby-electric-delimiters-alist + '((?\{ :name "Curly brace" :handler ruby-electric-curlies :closing ?\}) + (?\[ :name "Square brace" :handler ruby-electric-matching-char :closing ?\]) + (?\( :name "Round brace" :handler ruby-electric-matching-char :closing ?\)) + (?\' :name "Quote" :handler ruby-electric-matching-char) + (?\" :name "Double quote" :handler ruby-electric-matching-char) + (?\` :name "Back quote" :handler ruby-electric-matching-char) + (?\| :name "Vertical bar" :handler ruby-electric-bar) + (?\# :name "Hash" :handler ruby-electric-hash))) + +(defvar ruby-electric-matching-delimeter-alist + (apply 'nconc + (mapcar #'(lambda (x) + (let ((delim (car x)) + (plist (cdr x))) + (if (eq (plist-get plist :handler) 'ruby-electric-matching-char) + (list (cons delim (or (plist-get plist :closing) + delim)))))) + ruby-electric-delimiters-alist))) + +(defvar ruby-electric-expandable-keyword-re) + +(defmacro ruby-electric--try-insert-and-do (string &rest body) + (declare (indent 1)) + `(let ((before (point)) + (after (progn + (insert ,string) + (point)))) + (unwind-protect + (progn ,@body) + (delete-region before after) + (goto-char before)))) + +(defconst ruby-modifier-beg-symbol-re + (regexp-opt ruby-modifier-beg-keywords 'symbols)) + +(defun ruby-electric--modifier-keyword-at-point-p () + "Test if there is a modifier keyword at point." + (and (looking-at ruby-modifier-beg-symbol-re) + (let ((end (match-end 1))) + (not (looking-back "\\.")) + (save-excursion + (let ((indent1 (ruby-electric--try-insert-and-do "\n" + (ruby-calculate-indent))) + (indent2 (save-excursion + (goto-char end) + (ruby-electric--try-insert-and-do " x\n" + (ruby-calculate-indent))))) + (= indent1 indent2)))))) + +(defconst ruby-block-mid-symbol-re + (regexp-opt ruby-block-mid-keywords 'symbols)) + +(defun ruby-electric--block-mid-keyword-at-point-p () + "Test if there is a block mid keyword at point." + (and (looking-at ruby-block-mid-symbol-re) + (looking-back "^\\s-*"))) + +(defconst ruby-block-beg-symbol-re + (regexp-opt ruby-block-beg-keywords 'symbols)) + +(defun ruby-electric--block-beg-keyword-at-point-p () + "Test if there is a block beginning keyword at point." + (and (looking-at ruby-block-beg-symbol-re) + (if (string= (match-string 1) "do") + (looking-back "\\s-") + (not (looking-back "\\."))) + ;; (not (ruby-electric--modifier-keyword-at-point-p)) ;; implicit assumption + )) + +(defcustom ruby-electric-keywords-alist + '(("begin" . end) + ("case" . end) + ("class" . end) + ("def" . end) + ("do" . end) + ("else" . reindent) + ("elsif" . reindent) + ("end" . reindent) + ("ensure" . reindent) + ("for" . end) + ("if" . end) + ("module" . end) + ("rescue" . reindent) + ("unless" . end) + ("until" . end) + ("when" . reindent) + ("while" . end)) + "Alist of keywords and actions to define how to react to space +or return right after each keyword. In each (KEYWORD . ACTION) +cons, ACTION can be set to one of the following values: + + `reindent' Reindent the line. + + `end' Reindent the line and auto-close the keyword with + end if applicable. + + `nil' Do nothing. +" + :type '(repeat (cons (string :tag "Keyword") + (choice :tag "Action" + :menu-tag "Action" + (const :tag "Auto-close with end" + :value end) + (const :tag "Auto-reindent" + :value reindent) + (const :tag "None" + :value nil)))) + :set (lambda (sym val) + (set sym val) + (let (keywords) + (dolist (x val) + (let ((keyword (car x)) + (action (cdr x))) + (if action + (setq keywords (cons keyword keywords))))) + (setq ruby-electric-expandable-keyword-re + (concat (regexp-opt keywords 'symbols) + "$")))) + :group 'ruby-electric) + +(defcustom ruby-electric-simple-keywords-re nil + "Obsolete and ignored. Customize `ruby-electric-keywords-alist' +instead." + :type 'regexp :group 'ruby-electric) + +(defvar ruby-electric-mode-map + (let ((map (make-sparse-keymap))) + (define-key map " " 'ruby-electric-space/return) + (define-key map [remap delete-backward-char] 'ruby-electric-delete-backward-char) + (define-key map [remap newline] 'ruby-electric-space/return) + (define-key map [remap newline-and-indent] 'ruby-electric-space/return) + (dolist (x ruby-electric-delimiters-alist) + (let* ((delim (car x)) + (plist (cdr x)) + (name (plist-get plist :name)) + (func (plist-get plist :handler)) + (closing (plist-get plist :closing))) + (define-key map (char-to-string delim) func) + (if closing + (define-key map (char-to-string closing) 'ruby-electric-closing-char)))) + map) + "Keymap used in ruby-electric-mode") + +(defcustom ruby-electric-expand-delimiters-list '(all) + "*List of contexts where matching delimiter should be inserted. +The word 'all' will do all insertions." + :type `(set :extra-offset 8 + (const :tag "Everything" all) + ,@(apply 'list + (mapcar #'(lambda (x) + `(const :tag ,(plist-get (cdr x) :name) + ,(car x))) + ruby-electric-delimiters-alist))) + :group 'ruby-electric) + +(defcustom ruby-electric-newline-before-closing-bracket nil + "*Non-nil means a newline should be inserted before an +automatically inserted closing bracket." + :type 'boolean :group 'ruby-electric) + +(defcustom ruby-electric-autoindent-on-closing-char nil + "*Non-nil means the current line should be automatically +indented when a closing character is manually typed in." + :type 'boolean :group 'ruby-electric) + +(defvar ruby-electric-mode-hook nil + "Called after `ruby-electric-mode' is turned on.") + +;;;###autoload +(define-minor-mode ruby-electric-mode + "Toggle Ruby Electric minor mode. +With no argument, this command toggles the mode. Non-null prefix +argument turns on the mode. Null prefix argument turns off the +mode. + +When Ruby Electric mode is enabled, an indented 'end' is +heuristicaly inserted whenever typing a word like 'module', +'class', 'def', 'if', 'unless', 'case', 'until', 'for', 'begin', +'do' followed by a space. Single, double and back quotes as well +as braces are paired auto-magically. Expansion does not occur +inside comments and strings. Note that you must have Font Lock +enabled." + ;; initial value. + nil + ;;indicator for the mode line. + " REl" + ;;keymap + ruby-electric-mode-map + (if ruby-electric-mode + (run-hooks 'ruby-electric-mode-hook))) + +(defun ruby-electric-space/return-fallback () + (if (or (eq this-original-command 'ruby-electric-space/return) + (null (ignore-errors + ;; ac-complete may fail if there is nothing left to complete + (call-interactively this-original-command) + (setq this-command this-original-command)))) + ;; fall back to a globally bound command + (let ((command (global-key-binding (char-to-string last-command-event) t))) + (and command + (call-interactively (setq this-command command)))))) + +(defun ruby-electric-space/return (arg) + (interactive "*P") + (and (boundp 'sp-last-operation) + (setq sp-delayed-pair nil)) + (cond (arg + (insert (make-string (prefix-numeric-value arg) last-command-event))) + ((ruby-electric-space/return-can-be-expanded-p) + (let (action) + (save-excursion + (goto-char (match-beginning 0)) + (let* ((keyword (match-string 1)) + (allowed-actions + (cond ((ruby-electric--modifier-keyword-at-point-p) + '(reindent)) ;; no end necessary + ((ruby-electric--block-mid-keyword-at-point-p) + '(reindent)) ;; ditto + ((ruby-electric--block-beg-keyword-at-point-p) + '(end reindent))))) + (if allowed-actions + (setq action + (let ((action (cdr (assoc keyword ruby-electric-keywords-alist)))) + (and (memq action allowed-actions) + action)))))) + (cond ((eq action 'end) + (ruby-indent-line) + (save-excursion + (newline) + (ruby-insert-end))) + ((eq action 'reindent) + (ruby-indent-line))) + (ruby-electric-space/return-fallback))) + ((and (eq this-original-command 'newline-and-indent) + (ruby-electric-comment-at-point-p)) + (call-interactively (setq this-command 'comment-indent-new-line))) + (t + (ruby-electric-space/return-fallback)))) + +(defun ruby-electric-code-at-point-p() + (and ruby-electric-mode + (let* ((properties (text-properties-at (point)))) + (and (null (memq 'font-lock-string-face properties)) + (null (memq 'font-lock-comment-face properties)))))) + +(defun ruby-electric-string-at-point-p() + (and ruby-electric-mode + (consp (memq 'font-lock-string-face (text-properties-at (point)))))) + +(defun ruby-electric-comment-at-point-p() + (and ruby-electric-mode + (consp (memq 'font-lock-comment-face (text-properties-at (point)))))) + +(defun ruby-electric-escaped-p() + (let ((f nil)) + (save-excursion + (while (char-equal ?\\ (preceding-char)) + (backward-char 1) + (setq f (not f)))) + f)) + +(defun ruby-electric-command-char-expandable-punct-p(char) + (or (memq 'all ruby-electric-expand-delimiters-list) + (memq char ruby-electric-expand-delimiters-list))) + +(defun ruby-electric-space/return-can-be-expanded-p() + (and (ruby-electric-code-at-point-p) + (looking-back ruby-electric-expandable-keyword-re))) + +(defun ruby-electric-cua-replace-region-maybe() + (let ((func (key-binding [remap self-insert-command]))) + (when (memq func '(cua-replace-region + sp--cua-replace-region)) + (setq this-original-command 'self-insert-command) + (funcall (setq this-command func)) + t))) + +(defmacro ruby-electric-insert (arg &rest body) + `(cond ((ruby-electric-cua-replace-region-maybe)) + ((and + (null ,arg) + (ruby-electric-command-char-expandable-punct-p last-command-event)) + (insert last-command-event) + ,@body) + (t + (setq this-command 'self-insert-command) + (insert (make-string (prefix-numeric-value ,arg) last-command-event))))) + +(defun ruby-electric-curlies(arg) + (interactive "*P") + (ruby-electric-insert + arg + (cond + ((ruby-electric-code-at-point-p) + (insert "}") + (backward-char 1) + (redisplay) + (cond + ((ruby-electric-string-at-point-p) ;; %w{}, %r{}, etc. + t) + (ruby-electric-newline-before-closing-bracket + (insert " ") + (save-excursion + (newline) + (ruby-indent-line t))) + (t + (insert " ") + (backward-char 1)))) + ((ruby-electric-string-at-point-p) + (save-excursion + (backward-char 1) + (cond + ((char-equal ?\# (preceding-char)) + (unless (save-excursion + (backward-char 1) + (ruby-electric-escaped-p)) + (forward-char 1) + (insert "}"))) + ((or + (ruby-electric-command-char-expandable-punct-p ?\#) + (ruby-electric-escaped-p)) + (setq this-command 'self-insert-command)) + (t + (insert "#") + (forward-char 1) + (insert "}"))))) + (t + (setq this-command 'self-insert-command))))) + +(defun ruby-electric-hash(arg) + (interactive "*P") + (ruby-electric-insert + arg + (and (ruby-electric-string-at-point-p) + (or (char-equal (following-char) ?') ;; likely to be in '' + (save-excursion + (backward-char 1) + (ruby-electric-escaped-p)) + (progn + (insert "{}") + (backward-char 1)))))) + +(defmacro ruby-electric-avoid-eob(&rest body) + `(if (eobp) + (save-excursion + (insert "\n") + (backward-char) + ,@body + (prog1 + (ruby-electric-string-at-point-p) + (delete-char 1))) + ,@body)) + +(defun ruby-electric-matching-char(arg) + (interactive "*P") + (ruby-electric-insert + arg + (let ((closing (cdr (assoc last-command-event + ruby-electric-matching-delimeter-alist)))) + (cond + ((char-equal closing last-command-event) + (if (and (not (ruby-electric-string-at-point-p)) + (ruby-electric-avoid-eob + (redisplay) + (ruby-electric-string-at-point-p))) + (save-excursion (insert closing)) + (and (eq last-command 'ruby-electric-matching-char) + (char-equal (following-char) closing) ;; repeated quotes + (delete-forward-char 1)) + (setq this-command 'self-insert-command))) + ((ruby-electric-code-at-point-p) + (save-excursion (insert closing))))))) + +(defun ruby-electric-closing-char(arg) + (interactive "*P") + (cond + ((ruby-electric-cua-replace-region-maybe)) + (arg + (setq this-command 'self-insert-command) + (insert (make-string (prefix-numeric-value arg) last-command-event))) + ((and + (eq last-command 'ruby-electric-curlies) + (= last-command-event ?})) ;; {} + (if (char-equal (following-char) ?\n) (delete-char 1)) + (delete-horizontal-space) + (forward-char)) + ((and + (= last-command-event (following-char)) + (memq last-command '(ruby-electric-matching-char + ruby-electric-closing-char))) ;; ()/[] and (())/[[]] + (forward-char)) + (t + (setq this-command 'self-insert-command) + (self-insert-command 1) + (if ruby-electric-autoindent-on-closing-char + (ruby-indent-line))))) + +(defun ruby-electric-bar(arg) + (interactive "*P") + (ruby-electric-insert + arg + (cond ((and (ruby-electric-code-at-point-p) + (looking-back ruby-electric-expandable-bar-re)) + (save-excursion (insert "|"))) + (t + (setq this-command 'self-insert-command))))) + +(defun ruby-electric-delete-backward-char(arg) + (interactive "*p") + (cond ((memq last-command '(ruby-electric-matching-char + ruby-electric-bar)) + (delete-char 1)) + ((eq last-command 'ruby-electric-curlies) + (cond ((eolp) + (cond ((char-equal (preceding-char) ?\s) + (setq this-command last-command)) + ((char-equal (preceding-char) ?{) + (and (looking-at "[ \t\n]*}") + (delete-char (- (match-end 0) (match-beginning 0))))))) + ((char-equal (following-char) ?\s) + (setq this-command last-command) + (delete-char 1)) + ((char-equal (following-char) ?}) + (delete-char 1)))) + ((eq last-command 'ruby-electric-hash) + (and (char-equal (preceding-char) ?{) + (delete-char 1)))) + (delete-char (- arg))) + +(provide 'ruby-electric) + +;;; ruby-electric.el ends here diff --git a/jni/ruby/misc/ruby-mode.el b/jni/ruby/misc/ruby-mode.el new file mode 100644 index 0000000..ba885e2 --- /dev/null +++ b/jni/ruby/misc/ruby-mode.el @@ -0,0 +1,1584 @@ +;;; ruby-mode.el --- Major mode for editing Ruby files + +;; Copyright (C) 1994, 1995, 1996 1997, 1998, 1999, 2000, 2001, +;; 2002,2003, 2004, 2005, 2006, 2007, 2008 +;; Free Software Foundation, Inc. + +;; Authors: Yukihiro Matsumoto, Nobuyoshi Nakada +;; URL: http://www.emacswiki.org/cgi-bin/wiki/RubyMode +;; Created: Fri Feb 4 14:49:13 JST 1994 +;; Keywords: languages ruby +;; Version: 0.9 + +;; This file is not part of GNU Emacs. However, a newer version of +;; ruby-mode is included in recent releases of GNU Emacs (version 23 +;; and up), but the new version is not guaranteed to be compatible +;; with older versions of Emacs or XEmacs. This file is the last +;; version that aims to keep this compatibility. + +;; You can also get the latest version from the Emacs Lisp Package +;; Archive: http://tromey.com/elpa + +;; This file is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; It is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with it. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Provides font-locking, indentation support, and navigation for Ruby code. +;; +;; If you're installing manually, you should add this to your .emacs +;; file after putting it on your load path: +;; +;; (autoload 'ruby-mode "ruby-mode" "Major mode for ruby files" t) +;; (add-to-list 'auto-mode-alist '("\\.rb$" . ruby-mode)) +;; (add-to-list 'interpreter-mode-alist '("ruby" . ruby-mode)) +;; + +;;; Code: + +(defconst ruby-mode-revision "$Revision: 44033 $" + "Ruby mode revision string.") + +(defconst ruby-mode-version + (and (string-match "[0-9.]+" ruby-mode-revision) + (substring ruby-mode-revision (match-beginning 0) (match-end 0))) + "Ruby mode version number.") + +(defconst ruby-keyword-end-re + (if (string-match "\\_>" "ruby") + "\\_>" + "\\>")) + +(defconst ruby-block-beg-keywords + '("class" "module" "def" "if" "unless" "case" "while" "until" "for" "begin" "do") + "Keywords at the beginning of blocks.") + +(defconst ruby-block-beg-re + (regexp-opt ruby-block-beg-keywords) + "Regexp to match the beginning of blocks.") + +(defconst ruby-non-block-do-re + (concat (regexp-opt '("while" "until" "for" "rescue") t) ruby-keyword-end-re) + "Regexp to match") + +(defconst ruby-indent-beg-re + (concat "\\(\\s *" (regexp-opt '("class" "module" "def") t) "\\)\\|" + (regexp-opt '("if" "unless" "case" "while" "until" "for" "begin"))) + "Regexp to match where the indentation gets deeper.") + +(defconst ruby-modifier-beg-keywords + '("if" "unless" "while" "until") + "Modifiers that are the same as the beginning of blocks.") + +(defconst ruby-modifier-beg-re + (regexp-opt ruby-modifier-beg-keywords) + "Regexp to match modifiers same as the beginning of blocks.") + +(defconst ruby-modifier-re + (regexp-opt (cons "rescue" ruby-modifier-beg-keywords)) + "Regexp to match modifiers.") + +(defconst ruby-block-mid-keywords + '("then" "else" "elsif" "when" "rescue" "ensure") + "Keywords where the indentation gets shallower in middle of block statements.") + +(defconst ruby-block-mid-re + (regexp-opt ruby-block-mid-keywords) + "Regexp to match where the indentation gets shallower in middle of block statements.") + +(defconst ruby-block-op-keywords + '("and" "or" "not") + "Block operators.") + +(defconst ruby-block-hanging-re + (regexp-opt (append ruby-modifier-beg-keywords ruby-block-op-keywords)) + "Regexp to match hanging block modifiers.") + +(defconst ruby-block-end-re "\\_<end\\_>") + +(defconst ruby-here-doc-beg-re + "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)") + +(defconst ruby-here-doc-end-re + "^\\([ \t]+\\)?\\(.*\\)\\(.\\)$") + +(defun ruby-here-doc-end-match () + (concat "^" + (if (match-string 2) "[ \t]*" nil) + (regexp-quote + (or (match-string 4) + (match-string 5) + (match-string 6))))) + +(defun ruby-here-doc-beg-match () + (let ((contents (concat + (regexp-quote (concat (match-string 2) (match-string 3))) + (if (string= (match-string 3) "_") "\\B" "\\b")))) + (concat "<<" + (let ((match (match-string 1))) + (if (and match (> (length match) 0)) + (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)" (match-string 1) "\\)" + contents "\\(\\1\\|\\2\\)") + (concat "-?\\([\"']\\|\\)" contents "\\1")))))) + +(defconst ruby-delimiter + (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\_<\\(" + ruby-block-beg-re + "\\)\\_>\\|" ruby-block-end-re + "\\|^=begin\\|" ruby-here-doc-beg-re) + ) + +(defconst ruby-negative + (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\>\\|" + ruby-block-end-re "\\|}\\|\\]\\)") + "Regexp to match where the indentation gets shallower.") + +(defconst ruby-operator-chars "-,.+*/%&|^~=<>:") +(defconst ruby-operator-re (concat "[" ruby-operator-chars "]")) + +(defconst ruby-symbol-chars "a-zA-Z0-9_") +(defconst ruby-symbol-re (concat "[" ruby-symbol-chars "]")) + +(defvar ruby-mode-abbrev-table nil + "Abbrev table in use in ruby-mode buffers.") + +(define-abbrev-table 'ruby-mode-abbrev-table ()) + +(defvar ruby-mode-map nil "Keymap used in ruby mode.") + +(if ruby-mode-map + nil + (setq ruby-mode-map (make-sparse-keymap)) + (define-key ruby-mode-map "{" 'ruby-electric-brace) + (define-key ruby-mode-map "}" 'ruby-electric-brace) + (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun) + (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun) + (define-key ruby-mode-map "\e\C-b" 'ruby-backward-sexp) + (define-key ruby-mode-map "\e\C-f" 'ruby-forward-sexp) + (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block) + (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block) + (define-key ruby-mode-map "\e\C-h" 'ruby-mark-defun) + (define-key ruby-mode-map "\e\C-q" 'ruby-indent-exp) + (define-key ruby-mode-map "\t" 'ruby-indent-command) + (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end) + (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent) + (define-key ruby-mode-map "\C-c{" 'ruby-toggle-block) + (define-key ruby-mode-map "\C-c\C-u" 'uncomment-region)) + +(defvar ruby-mode-syntax-table nil + "Syntax table in use in ruby-mode buffers.") + +(if ruby-mode-syntax-table + () + (setq ruby-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\' "\"" ruby-mode-syntax-table) + (modify-syntax-entry ?\" "\"" ruby-mode-syntax-table) + (modify-syntax-entry ?\` "\"" ruby-mode-syntax-table) + (modify-syntax-entry ?# "<" ruby-mode-syntax-table) + (modify-syntax-entry ?\n ">" ruby-mode-syntax-table) + (modify-syntax-entry ?\\ "\\" ruby-mode-syntax-table) + (modify-syntax-entry ?$ "." ruby-mode-syntax-table) + (modify-syntax-entry ?? "_" ruby-mode-syntax-table) + (modify-syntax-entry ?_ "_" ruby-mode-syntax-table) + (modify-syntax-entry ?: "_" ruby-mode-syntax-table) + (modify-syntax-entry ?< "." ruby-mode-syntax-table) + (modify-syntax-entry ?> "." ruby-mode-syntax-table) + (modify-syntax-entry ?& "." ruby-mode-syntax-table) + (modify-syntax-entry ?| "." ruby-mode-syntax-table) + (modify-syntax-entry ?% "." ruby-mode-syntax-table) + (modify-syntax-entry ?= "." ruby-mode-syntax-table) + (modify-syntax-entry ?/ "." ruby-mode-syntax-table) + (modify-syntax-entry ?+ "." ruby-mode-syntax-table) + (modify-syntax-entry ?* "." ruby-mode-syntax-table) + (modify-syntax-entry ?- "." ruby-mode-syntax-table) + (modify-syntax-entry ?\; "." ruby-mode-syntax-table) + (modify-syntax-entry ?\( "()" ruby-mode-syntax-table) + (modify-syntax-entry ?\) ")(" ruby-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" ruby-mode-syntax-table) + (modify-syntax-entry ?\} "){" ruby-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" ruby-mode-syntax-table) + (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table) + ) + +(defcustom ruby-indent-tabs-mode nil + "*Indentation can insert tabs in ruby mode if this is non-nil." + :type 'boolean :group 'ruby) +(put 'ruby-indent-tabs-mode 'safe-local-variable 'booleanp) + +(defcustom ruby-indent-level 2 + "*Indentation of ruby statements." + :type 'integer :group 'ruby) +(put 'ruby-indent-level 'safe-local-variable 'integerp) + +(defcustom ruby-comment-column 32 + "*Indentation column of comments." + :type 'integer :group 'ruby) +(put 'ruby-comment-column 'safe-local-variable 'integerp) + +(defcustom ruby-deep-arglist t + "*Deep indent lists in parenthesis when non-nil. +Also ignores spaces after parenthesis when 'space." + :group 'ruby) +(put 'ruby-deep-arglist 'safe-local-variable 'booleanp) + +(defcustom ruby-deep-indent-paren '(?\( ?\[ ?\] t) + "*Deep indent lists in parenthesis when non-nil. t means continuous line. +Also ignores spaces after parenthesis when 'space." + :group 'ruby) + +(defcustom ruby-deep-indent-paren-style 'space + "Default deep indent style." + :options '(t nil space) :group 'ruby) + +(defcustom ruby-encoding-map + '((us-ascii . nil) ;; Do not put coding: us-ascii + (utf-8 . nil) ;; Do not put coding: utf-8 + (shift-jis . cp932) ;; Emacs charset name of Shift_JIS + (shift_jis . cp932) ;; MIME charset name of Shift_JIS + (japanese-cp932 . cp932)) ;; Emacs charset name of CP932 + "Alist to map encoding name from Emacs to Ruby. +Associating an encoding name with nil means it needs not be +explicitly declared in magic comment." + :type '(repeat (cons (symbol :tag "From") (symbol :tag "To"))) + :group 'ruby) + +(defcustom ruby-use-encoding-map t + "*Use `ruby-encoding-map' to set encoding magic comment if this is non-nil." + :type 'boolean :group 'ruby) + +(defvar ruby-indent-point nil "internal variable") + +(eval-when-compile (require 'cl)) +(defun ruby-imenu-create-index-in-block (prefix beg end) + (let ((index-alist '()) (case-fold-search nil) + name next pos decl sing) + (goto-char beg) + (while (re-search-forward "^\\s *\\(\\(class\\s +\\|\\(class\\s *<<\\s *\\)\\|module\\s +\\)\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\s +\\([^\(\n ]+\\)\\)" end t) + (setq sing (match-beginning 3)) + (setq decl (match-string 5)) + (setq next (match-end 0)) + (setq name (or (match-string 4) (match-string 6))) + (setq pos (match-beginning 0)) + (cond + ((string= "alias" decl) + (if prefix (setq name (concat prefix name))) + (push (cons name pos) index-alist)) + ((string= "def" decl) + (if prefix + (setq name + (cond + ((string-match "^self\." name) + (concat (substring prefix 0 -1) (substring name 4))) + (t (concat prefix name))))) + (push (cons name pos) index-alist) + (ruby-accurate-end-of-block end)) + (t + (if (string= "self" name) + (if prefix (setq name (substring prefix 0 -1))) + (if prefix (setq name (concat (substring prefix 0 -1) "::" name))) + (push (cons name pos) index-alist)) + (ruby-accurate-end-of-block end) + (setq beg (point)) + (setq index-alist + (nconc (ruby-imenu-create-index-in-block + (concat name (if sing "." "#")) + next beg) index-alist)) + (goto-char beg)))) + index-alist)) + +(defun ruby-imenu-create-index () + (nreverse (ruby-imenu-create-index-in-block nil (point-min) nil))) + +(defun ruby-accurate-end-of-block (&optional end) + (let (state) + (or end (setq end (point-max))) + (while (and (setq state (apply 'ruby-parse-partial end state)) + (>= (nth 2 state) 0) (< (point) end))))) + +(defun ruby-mode-variables () + (set-syntax-table ruby-mode-syntax-table) + (setq show-trailing-whitespace t) + (setq local-abbrev-table ruby-mode-abbrev-table) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'ruby-indent-line) + (make-local-variable 'require-final-newline) + (setq require-final-newline t) + (make-local-variable 'comment-start) + (setq comment-start "# ") + (make-local-variable 'comment-end) + (setq comment-end "") + (make-local-variable 'comment-column) + (setq comment-column ruby-comment-column) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "#+ *") + (setq indent-tabs-mode ruby-indent-tabs-mode) + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments t) + (make-local-variable 'parse-sexp-lookup-properties) + (setq parse-sexp-lookup-properties t) + (make-local-variable 'paragraph-start) + (setq paragraph-start (concat "$\\|" page-delimiter)) + (make-local-variable 'paragraph-separate) + (setq paragraph-separate paragraph-start) + (make-local-variable 'paragraph-ignore-fill-prefix) + (setq paragraph-ignore-fill-prefix t)) + +(defun ruby-mode-set-encoding () + "Insert or update a magic comment header with the proper encoding. +`ruby-encoding-map' is looked up to convert an encoding name from +Emacs to Ruby." + (let* ((nonascii + (save-excursion + (widen) + (goto-char (point-min)) + (re-search-forward "[^\0-\177]" nil t))) + (coding-system + (or coding-system-for-write + buffer-file-coding-system)) + (coding-system + (and coding-system + (coding-system-change-eol-conversion coding-system nil))) + (coding-system + (and coding-system + (or + (coding-system-get coding-system :mime-charset) + (let ((coding-type (coding-system-get coding-system :coding-type))) + (cond ((eq coding-type 'undecided) + (if nonascii + (or (and (coding-system-get coding-system :prefer-utf-8) + 'utf-8) + (coding-system-get default-buffer-file-coding-system :coding-type) + 'ascii-8bit))) + ((memq coding-type '(utf-8 shift-jis)) + coding-type) + (t coding-system)))))) + (coding-system + (or coding-system + 'us-ascii)) + (coding-system + (let ((cons (assq coding-system ruby-encoding-map))) + (if cons (cdr cons) coding-system))) + (coding-system + (and coding-system + (symbol-name coding-system)))) + (if coding-system + (save-excursion + (widen) + (goto-char (point-min)) + (if (looking-at "^#!") (beginning-of-line 2)) + (cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)\\s *\\(;\\|-\*-\\)") + (unless (string= (match-string 2) coding-system) + (goto-char (match-beginning 2)) + (delete-region (point) (match-end 2)) + (and (looking-at "-\*-") + (let ((n (skip-chars-backward " "))) + (cond ((= n 0) (insert " ") (backward-char)) + ((= n -1) (insert " ")) + ((forward-char))))) + (insert coding-system))) + ((looking-at "\\s *#.*coding\\s *[:=]")) + (t (when ruby-insert-encoding-magic-comment + (insert "# -*- coding: " coding-system " -*-\n")))))))) + +(defun ruby-current-indentation () + (save-excursion + (beginning-of-line) + (back-to-indentation) + (current-column))) + +(defun ruby-indent-line (&optional flag) + "Correct indentation of the current ruby line." + (ruby-indent-to (ruby-calculate-indent))) + +(defun ruby-indent-command () + (interactive) + (ruby-indent-line t)) + +(defun ruby-indent-to (x) + (if x + (let (shift top beg) + (and (< x 0) (error "invalid nest")) + (setq shift (current-column)) + (beginning-of-line) + (setq beg (point)) + (back-to-indentation) + (setq top (current-column)) + (skip-chars-backward " \t") + (if (>= shift top) (setq shift (- shift top)) + (setq shift 0)) + (if (and (bolp) + (= x top)) + (move-to-column (+ x shift)) + (move-to-column top) + (delete-region beg (point)) + (beginning-of-line) + (indent-to x) + (move-to-column (+ x shift)))))) + +(defun ruby-special-char-p (&optional pnt) + (setq pnt (or pnt (point))) + (let ((c (char-before pnt)) (b (and (< (point-min) pnt) (char-before (1- pnt))))) + (cond ((or (eq c ??) (eq c ?$))) + ((and (eq c ?:) (or (not b) (eq (char-syntax b) ? )))) + ((eq c ?\\) (eq b ??))))) + +(defun ruby-singleton-class-p () + (save-excursion + (forward-word -1) + (and (or (bolp) (not (eq (char-before (point)) ?_))) + (looking-at "class\\s *<<")))) + +(defun ruby-expr-beg (&optional option) + (save-excursion + (store-match-data nil) + (let ((space (skip-chars-backward " \t")) + (start (point))) + (cond + ((bolp) t) + ((progn + (forward-char -1) + (and (looking-at "\\?") + (or (eq (char-syntax (preceding-char)) ?w) + (ruby-special-char-p)))) + nil) + ((and (eq option 'heredoc) (< space 0)) + (not (progn (goto-char start) (ruby-singleton-class-p)))) + ((or (looking-at ruby-operator-re) + (looking-at "[\\[({,;]") + (and (looking-at "[!?]") + (or (not (eq option 'modifier)) + (bolp) + (save-excursion (forward-char -1) (looking-at "\\Sw$")))) + (and (looking-at ruby-symbol-re) + (skip-chars-backward ruby-symbol-chars) + (cond + ((looking-at (regexp-opt + (append ruby-block-beg-keywords + ruby-block-op-keywords + ruby-block-mid-keywords) + 'words)) + (goto-char (match-end 0)) + (not (looking-at "\\s_\\|[!?:]"))) + ((eq option 'expr-qstr) + (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]")) + ((eq option 'expr-re) + (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]")) + (t nil))))))))) + +(defun ruby-forward-string (term &optional end no-error expand) + (let ((n 1) (c (string-to-char term)) + (re (if expand + (concat "[^\\]\\(\\\\\\\\\\)*\\([" term "]\\|\\(#{\\)\\)") + (concat "[^\\]\\(\\\\\\\\\\)*[" term "]")))) + (while (and (re-search-forward re end no-error) + (if (match-beginning 3) + (ruby-forward-string "}{" end no-error nil) + (> (setq n (if (eq (char-before (point)) c) + (1- n) (1+ n))) 0))) + (forward-char -1)) + (cond ((zerop n)) + (no-error nil) + ((error "unterminated string"))))) + +(defun ruby-deep-indent-paren-p (c &optional pos) + (cond ((save-excursion + (if pos (goto-char pos)) + (ruby-expr-beg)) + nil) + ((listp ruby-deep-indent-paren) + (let ((deep (assoc c ruby-deep-indent-paren))) + (cond (deep + (or (cdr deep) ruby-deep-indent-paren-style)) + ((memq c ruby-deep-indent-paren) + ruby-deep-indent-paren-style)))) + ((eq c ruby-deep-indent-paren) ruby-deep-indent-paren-style) + ((eq c ?\( ) ruby-deep-arglist))) + +(defun ruby-parse-partial (&optional end in-string nest depth pcol indent) + (or depth (setq depth 0)) + (or indent (setq indent 0)) + (when (re-search-forward ruby-delimiter end 'move) + (let ((pnt (point)) w re expand) + (goto-char (match-beginning 0)) + (cond + ((and (memq (char-before) '(?@ ?$)) (looking-at "\\sw")) + (goto-char pnt)) + ((looking-at "[\"`]") ;skip string + (cond + ((and (not (eobp)) + (ruby-forward-string (buffer-substring (point) (1+ (point))) end t t)) + nil) + (t + (setq in-string (point)) + (goto-char end)))) + ((looking-at "'") + (cond + ((and (not (eobp)) + (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" end t)) + nil) + (t + (setq in-string (point)) + (goto-char end)))) + ((looking-at "/=") + (goto-char pnt)) + ((looking-at "/") + (cond + ((and (not (eobp)) (ruby-expr-beg 'expr-re)) + (if (ruby-forward-string "/" end t t) + nil + (setq in-string (point)) + (goto-char end))) + (t + (goto-char pnt)))) + ((looking-at "%") + (cond + ((and (not (eobp)) + (ruby-expr-beg 'expr-qstr) + (not (looking-at "%=")) + (looking-at "%[QqrxWw]?\\([^a-zA-Z0-9 \t\n]\\)")) + (goto-char (match-beginning 1)) + (setq expand (not (memq (char-before) '(?q ?w)))) + (setq w (match-string 1)) + (cond + ((string= w "[") (setq re "][")) + ((string= w "{") (setq re "}{")) + ((string= w "(") (setq re ")(")) + ((string= w "<") (setq re "><")) + ((and expand (string= w "\\")) + (setq w (concat "\\" w)))) + (unless (cond (re (ruby-forward-string re end t expand)) + (expand (ruby-forward-string w end t t)) + (t (re-search-forward + (if (string= w "\\") + "\\\\[^\\]*\\\\" + (concat "[^\\]\\(\\\\\\\\\\)*" w)) + end t))) + (setq in-string (point)) + (goto-char end))) + (t + (goto-char pnt)))) + ((looking-at "\\?") ;skip ?char + (cond + ((and (ruby-expr-beg) + (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?.")) + (goto-char (match-end 0))) + (t + (goto-char pnt)))) + ((looking-at "\\$") ;skip $char + (goto-char pnt) + (forward-char 1)) + ((looking-at "#") ;skip comment + (forward-line 1) + (goto-char (point)) + ) + ((looking-at "[\\[{(]") + (let ((deep (ruby-deep-indent-paren-p (char-after)))) + (if (and deep (or (not (eq (char-after) ?\{)) (ruby-expr-beg))) + (progn + (and (eq deep 'space) (looking-at ".\\s +[^# \t\n]") + (setq pnt (1- (match-end 0)))) + (setq nest (cons (cons (char-after (point)) (point)) nest)) + (setq pcol (cons (cons pnt depth) pcol)) + (setq depth 0)) + (setq nest (cons (cons (char-after (point)) pnt) nest)) + (setq depth (1+ depth)))) + (goto-char pnt) + ) + ((looking-at "[])}]") + (if (ruby-deep-indent-paren-p (matching-paren (char-after)) + (if nest + (cdr (nth 0 nest)) + (save-excursion + (forward-char) + (ruby-backward-sexp) + (point)))) + (setq depth (cdr (car pcol)) pcol (cdr pcol)) + (setq depth (1- depth))) + (setq nest (cdr nest)) + (goto-char pnt)) + ((looking-at ruby-block-end-re) + (if (or (and (not (bolp)) + (progn + (forward-char -1) + (setq w (char-after (point))) + (or (eq ?_ w) + (eq ?. w)))) + (progn + (goto-char pnt) + (setq w (char-after (point))) + (or (eq ?_ w) + (eq ?! w) + (eq ?? w)))) + nil + (setq nest (cdr nest)) + (setq depth (1- depth))) + (goto-char pnt)) + ((looking-at "def\\s +[^(\n;]*") + (if (or (bolp) + (progn + (forward-char -1) + (not (eq ?_ (char-after (point)))))) + (progn + (setq nest (cons (cons nil pnt) nest)) + (setq depth (1+ depth)))) + (goto-char (match-end 0))) + ((looking-at (concat "\\_<\\(" ruby-block-beg-re "\\)\\_>")) + (and + (save-match-data + (or (not (looking-at (concat "do" ruby-keyword-end-re))) + (save-excursion + (back-to-indentation) + (not (looking-at ruby-non-block-do-re))))) + (or (bolp) + (progn + (forward-char -1) + (setq w (char-after (point))) + (not (or (eq ?_ w) + (eq ?. w))))) + (goto-char pnt) + (setq w (char-after (point))) + (not (eq ?_ w)) + (not (eq ?! w)) + (not (eq ?? w)) + (not (eq ?: w)) + (skip-chars-forward " \t") + (goto-char (match-beginning 0)) + (or (not (looking-at ruby-modifier-re)) + (ruby-expr-beg 'modifier)) + (goto-char pnt) + (setq nest (cons (cons nil pnt) nest)) + (setq depth (1+ depth))) + (goto-char pnt)) + ((looking-at ":\\(['\"]\\)") + (goto-char (match-beginning 1)) + (ruby-forward-string (buffer-substring (match-beginning 1) (match-end 1)) end)) + ((looking-at ":\\([-,.+*/%&|^~<>]=?\\|===?\\|<=>\\|![~=]?\\)") + (goto-char (match-end 0))) + ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*[!?=]?\\)?") + (goto-char (match-end 0))) + ((or (looking-at "\\.\\.\\.?") + (looking-at "\\.[0-9]+") + (looking-at "\\.[a-zA-Z_0-9]+") + (looking-at "\\.")) + (goto-char (match-end 0))) + ((looking-at "^=begin") + (if (re-search-forward "^=end" end t) + (forward-line 1) + (setq in-string (match-end 0)) + (goto-char end))) + ((looking-at "<<") + (cond + ((and (ruby-expr-beg 'heredoc) + (looking-at "<<\\(-\\)?\\(\\([\"'`]\\)\\([^\n]+?\\)\\3\\|\\(?:\\sw\\|\\s_\\)+\\)")) + (setq re (regexp-quote (or (match-string 4) (match-string 2)))) + (if (match-beginning 1) (setq re (concat "\\s *" re))) + (let* ((id-end (goto-char (match-end 0))) + (line-end-position (save-excursion (end-of-line) (point))) + (state (list in-string nest depth pcol indent))) + ;; parse the rest of the line + (while (and (> line-end-position (point)) + (setq state (apply 'ruby-parse-partial + line-end-position state)))) + (setq in-string (car state) + nest (nth 1 state) + depth (nth 2 state) + pcol (nth 3 state) + indent (nth 4 state)) + ;; skip heredoc section + (if (re-search-forward (concat "^" re "$") end 'move) + (forward-line 1) + (setq in-string id-end) + (goto-char end)))) + (t + (goto-char pnt)))) + ((looking-at "^__END__$") + (goto-char pnt)) + ((looking-at ruby-here-doc-beg-re) + (if (re-search-forward (ruby-here-doc-end-match) + ruby-indent-point t) + (forward-line 1) + (setq in-string (match-end 0)) + (goto-char ruby-indent-point))) + (t + (error (format "bad string %s" + (buffer-substring (point) pnt) + )))))) + (list in-string nest depth pcol)) + +(defun ruby-parse-region (start end) + (let (state) + (save-excursion + (if start + (goto-char start) + (ruby-beginning-of-indent)) + (save-restriction + (narrow-to-region (point) end) + (while (and (> end (point)) + (setq state (apply 'ruby-parse-partial end state)))))) + (list (nth 0 state) ; in-string + (car (nth 1 state)) ; nest + (nth 2 state) ; depth + (car (car (nth 3 state))) ; pcol + ;(car (nth 5 state)) ; indent + ))) + +(defun ruby-indent-size (pos nest) + (+ pos (* (or nest 1) ruby-indent-level))) + +(defun ruby-calculate-indent (&optional parse-start) + (save-excursion + (beginning-of-line) + (let ((ruby-indent-point (point)) + (case-fold-search nil) + state bol eol begin op-end + (paren (progn (skip-syntax-forward " ") + (and (char-after) (matching-paren (char-after))))) + (indent 0)) + (if parse-start + (goto-char parse-start) + (ruby-beginning-of-indent) + (setq parse-start (point))) + (back-to-indentation) + (setq indent (current-column)) + (setq state (ruby-parse-region parse-start ruby-indent-point)) + (cond + ((nth 0 state) ; within string + (setq indent nil)) ; do nothing + ((car (nth 1 state)) ; in paren + (goto-char (setq begin (cdr (nth 1 state)))) + (let ((deep (ruby-deep-indent-paren-p (car (nth 1 state)) + (1- (cdr (nth 1 state)))))) + (if deep + (cond ((and (eq deep t) (eq (car (nth 1 state)) paren)) + (skip-syntax-backward " ") + (setq indent (1- (current-column)))) + ((eq deep 'space) + (goto-char (cdr (nth 1 state))) + (setq indent (1+ (current-column)))) + ((let ((s (ruby-parse-region (point) ruby-indent-point))) + (and (nth 2 s) (> (nth 2 s) 0) + (or (goto-char (cdr (nth 1 s))) t))) + (forward-word -1) + (setq indent (ruby-indent-size (current-column) (nth 2 state)))) + (t + (setq indent (current-column)) + (cond ((eq deep 'space)) + (paren (setq indent (1- indent))) + (t (setq indent (ruby-indent-size (1- indent) 1)))))) + (if (nth 3 state) (goto-char (nth 3 state)) + (goto-char parse-start) (back-to-indentation)) + (setq indent (ruby-indent-size (current-column) (nth 2 state)))) + (and (eq (car (nth 1 state)) paren) + (ruby-deep-indent-paren-p (matching-paren paren) + (1- (cdr (nth 1 state)))) + (search-backward (char-to-string paren)) + (setq indent (current-column))))) + ((and (nth 2 state) (> (nth 2 state) 0)) ; in nest + (if (null (cdr (nth 1 state))) + (error "invalid nest")) + (goto-char (cdr (nth 1 state))) + (forward-word -1) ; skip back a keyword + (setq begin (point)) + (cond + ((looking-at "do\\>[^_]") ; iter block is a special case + (if (nth 3 state) (goto-char (nth 3 state)) + (goto-char parse-start) (back-to-indentation)) + (setq indent (ruby-indent-size (current-column) (nth 2 state)))) + (t + (setq indent (+ (current-column) ruby-indent-level))))) + + ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest + (setq indent (ruby-indent-size (current-column) (nth 2 state))))) + (when indent + (goto-char ruby-indent-point) + (end-of-line) + (setq eol (point)) + (beginning-of-line) + (cond + ((and (not (ruby-deep-indent-paren-p paren + (and (cdr (nth 1 state)) + (1- (cdr (nth 1 state)))))) + (re-search-forward ruby-negative eol t)) + (and (not (eq ?_ (char-after (match-end 0)))) + (setq indent (- indent ruby-indent-level)))) + ((and + (save-excursion + (beginning-of-line) + (not (bobp))) + (or (ruby-deep-indent-paren-p t) + (null (car (nth 1 state))))) + ;; goto beginning of non-empty no-comment line + (let (end done) + (while (not done) + (skip-chars-backward " \t\n") + (setq end (point)) + (beginning-of-line) + (if (re-search-forward "^\\s *#" end t) + (beginning-of-line) + (setq done t)))) + (setq bol (point)) + (end-of-line) + ;; skip the comment at the end + (skip-chars-backward " \t") + (let (end (pos (point))) + (beginning-of-line) + (while (and (re-search-forward "#" pos t) + (setq end (1- (point))) + (or (ruby-special-char-p end) + (and (setq state (ruby-parse-region parse-start end)) + (nth 0 state)))) + (setq end nil)) + (goto-char (or end pos)) + (skip-chars-backward " \t") + (setq begin (if (and end (nth 0 state)) pos (cdr (nth 1 state)))) + (setq state (ruby-parse-region parse-start (point)))) + (or (bobp) (forward-char -1)) + (and + (or (and (looking-at ruby-symbol-re) + (skip-chars-backward ruby-symbol-chars) + (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>")) + (not (eq (point) (nth 3 state))) + (save-excursion + (goto-char (match-end 0)) + (not (looking-at "[a-z_]")))) + (and (looking-at ruby-operator-re) + (not (ruby-special-char-p)) + ;; operator at the end of line + (let ((c (char-after (point)))) + (and +;; (or (null begin) +;; (save-excursion +;; (goto-char begin) +;; (skip-chars-forward " \t") +;; (not (or (eolp) (looking-at "#") +;; (and (eq (car (nth 1 state)) ?{) +;; (looking-at "|")))))) + (or (not (eq ?/ c)) + (null (nth 0 (ruby-parse-region (or begin parse-start) (point))))) + (or (not (eq ?| (char-after (point)))) + (save-excursion + (or (eolp) (forward-char -1)) + (cond + ((search-backward "|" nil t) + (skip-chars-backward " \t\n") + (and (not (eolp)) + (progn + (forward-char -1) + (not (looking-at "{"))) + (progn + (forward-word -1) + (not (looking-at "do\\>[^_]"))))) + (t t)))) + (not (eq ?, c)) + (setq op-end t))))) + (setq indent + (cond + ((and + (null op-end) + (not (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>"))) + (eq (ruby-deep-indent-paren-p t) 'space) + (not (bobp))) + (widen) + (goto-char (or begin parse-start)) + (skip-syntax-forward " ") + (current-column)) + ((car (nth 1 state)) indent) + (t + (+ indent ruby-indent-level)))))))) + (goto-char ruby-indent-point) + (beginning-of-line) + (skip-syntax-forward " ") + (if (looking-at "\\.[^.]") + (+ indent ruby-indent-level) + indent)))) + +(defun ruby-electric-brace (arg) + (interactive "P") + (insert-char last-command-event 1) + (ruby-indent-line t) + (delete-char -1) + (self-insert-command (prefix-numeric-value arg))) + +(eval-when-compile + (defmacro defun-region-command (func args &rest body) + (let ((intr (car body))) + (when (featurep 'xemacs) + (if (stringp intr) (setq intr (cadr body))) + (and (eq (car intr) 'interactive) + (setq intr (cdr intr)) + (setcar intr (concat "_" (car intr))))) + (cons 'defun (cons func (cons args body)))))) + +(defun-region-command ruby-beginning-of-defun (&optional arg) + "Move backward to next beginning-of-defun. +With argument, do this that many times. +Returns t unless search stops due to end of buffer." + (interactive "p") + (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\_>") + nil 'move (or arg 1)) + (progn (beginning-of-line) t))) + +(defun ruby-beginning-of-indent () + (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\_>") + nil 'move) + (progn + (beginning-of-line) + t))) + +(defun-region-command ruby-end-of-defun (&optional arg) + "Move forward to next end of defun. +An end of a defun is found by moving forward from the beginning of one." + (interactive "p") + (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)") + nil 'move (or arg 1)) + (progn (beginning-of-line) t)) + (forward-line 1)) + +(defun ruby-move-to-block (n) + (let (start pos done down (orig (point))) + (setq start (ruby-calculate-indent)) + (setq down (looking-at (if (< n 0) ruby-block-end-re + (concat "\\<\\(" ruby-block-beg-re "\\)\\>")))) + (while (and (not done) (not (if (< n 0) (bobp) (eobp)))) + (forward-line n) + (cond + ((looking-at "^\\s *$")) + ((looking-at "^\\s *#")) + ((and (> n 0) (looking-at "^=begin\\>")) + (re-search-forward "^=end\\>")) + ((and (< n 0) (looking-at "^=end\\>")) + (re-search-backward "^=begin\\>")) + (t + (setq pos (current-indentation)) + (cond + ((< start pos) + (setq down t)) + ((and down (= pos start)) + (setq done t)) + ((> start pos) + (setq done t))))) + (if done + (save-excursion + (back-to-indentation) + (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>")) + (setq done nil))))) + (back-to-indentation) + (when (< n 0) + (let ((eol (point-at-eol)) state next) + (if (< orig eol) (setq eol orig)) + (setq orig (point)) + (while (and (setq next (apply 'ruby-parse-partial eol state)) + (< (point) eol)) + (setq state next)) + (when (cdaadr state) + (goto-char (cdaadr state))) + (backward-word))))) + +(defun-region-command ruby-beginning-of-block (&optional arg) + "Move backward to next beginning-of-block" + (interactive "p") + (ruby-move-to-block (- (or arg 1)))) + +(defun-region-command ruby-end-of-block (&optional arg) + "Move forward to next beginning-of-block" + (interactive "p") + (ruby-move-to-block (or arg 1))) + +(defun-region-command ruby-forward-sexp (&optional cnt) + (interactive "p") + (if (and (numberp cnt) (< cnt 0)) + (ruby-backward-sexp (- cnt)) + (let ((i (or cnt 1))) + (condition-case nil + (while (> i 0) + (skip-syntax-forward " ") + (if (looking-at ",\\s *") (goto-char (match-end 0))) + (cond ((looking-at "\\?\\(\\\\[CM]-\\)*\\\\?\\S ") + (goto-char (match-end 0))) + ((progn + (skip-chars-forward ",.:;|&^~=!?\\+\\-\\*") + (looking-at "\\s(")) + (goto-char (scan-sexps (point) 1))) + ((and (looking-at (concat "\\<\\(" ruby-block-beg-re "\\)\\>")) + (not (eq (char-before (point)) ?.)) + (not (eq (char-before (point)) ?:))) + (ruby-end-of-block) + (forward-word 1)) + ((looking-at "\\(\\$\\|@@?\\)?\\sw") + (while (progn + (while (progn (forward-word 1) (looking-at "_"))) + (cond ((looking-at "::") (forward-char 2) t) + ((> (skip-chars-forward ".") 0)) + ((looking-at "\\?\\|!\\(=[~=>]\\|[^~=]\\)") + (forward-char 1) nil))))) + ((let (state expr) + (while + (progn + (setq expr (or expr (ruby-expr-beg) + (looking-at "%\\sw?\\Sw\\|[\"'`/]"))) + (nth 1 (setq state (apply 'ruby-parse-partial nil state)))) + (setq expr t) + (skip-chars-forward "<")) + (not expr)))) + (setq i (1- i))) + ((error) (forward-word 1))) + i))) + +(defun-region-command ruby-backward-sexp (&optional cnt) + (interactive "p") + (if (and (numberp cnt) (< cnt 0)) + (ruby-forward-sexp (- cnt)) + (let ((i (or cnt 1))) + (condition-case nil + (while (> i 0) + (skip-chars-backward " \t\n,.:;|&^~=!?\\+\\-\\*") + (forward-char -1) + (cond ((looking-at "\\s)") + (goto-char (scan-sexps (1+ (point)) -1)) + (case (char-before) + (?% (forward-char -1)) + ('(?q ?Q ?w ?W ?r ?x) + (if (eq (char-before (1- (point))) ?%) (forward-char -2)))) + nil) + ((looking-at "\\s\"\\|\\\\\\S_") + (let ((c (char-to-string (char-before (match-end 0))))) + (while (and (search-backward c) + (oddp (skip-chars-backward "\\"))))) + nil) + ((looking-at "\\s.\\|\\s\\") + (if (ruby-special-char-p) (forward-char -1))) + ((looking-at "\\s(") nil) + (t + (forward-char 1) + (while (progn (forward-word -1) + (case (char-before) + (?_ t) + (?. (forward-char -1) t) + ((?$ ?@) + (forward-char -1) + (and (eq (char-before) (char-after)) (forward-char -1))) + (?: + (forward-char -1) + (eq (char-before) :))))) + (if (looking-at ruby-block-end-re) + (ruby-beginning-of-block)) + nil)) + (setq i (1- i))) + ((error))) + i))) + +(defun ruby-reindent-then-newline-and-indent () + (interactive "*") + (newline) + (save-excursion + (end-of-line 0) + (indent-according-to-mode) + (delete-region (point) (progn (skip-chars-backward " \t") (point)))) + (indent-according-to-mode)) + +(fset 'ruby-encomment-region (symbol-function 'comment-region)) + +(defun ruby-decomment-region (beg end) + (interactive "r") + (save-excursion + (goto-char beg) + (while (re-search-forward "^\\([ \t]*\\)#" end t) + (replace-match "\\1" nil nil) + (save-excursion + (ruby-indent-line))))) + +(defun ruby-insert-end () + (interactive) + (insert "end") + (ruby-indent-line t) + (end-of-line)) + +(defun ruby-mark-defun () + "Put mark at end of this Ruby function, point at beginning." + (interactive) + (push-mark (point)) + (ruby-end-of-defun) + (push-mark (point) nil t) + (ruby-beginning-of-defun) + (re-search-backward "^\n" (- (point) 1) t)) + +(defun ruby-indent-exp (&optional shutup-p) + "Indent each line in the balanced expression following point syntactically. +If optional SHUTUP-P is non-nil, no errors are signalled if no +balanced expression is found." + (interactive "*P") + (let ((here (point-marker)) start top column (nest t)) + (set-marker-insertion-type here t) + (unwind-protect + (progn + (beginning-of-line) + (setq start (point) top (current-indentation)) + (while (and (not (eobp)) + (progn + (setq column (ruby-calculate-indent start)) + (cond ((> column top) + (setq nest t)) + ((and (= column top) nest) + (setq nest nil) t)))) + (ruby-indent-to column) + (beginning-of-line 2))) + (goto-char here) + (set-marker here nil)))) + +(defun ruby-add-log-current-method () + "Return current method string." + (condition-case nil + (save-excursion + (let (mname mlist (indent 0)) + ;; get current method (or class/module) + (if (re-search-backward + (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+" + "\\(" + ;; \\. and :: for class method + "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" + "+\\)") + nil t) + (progn + (setq mname (match-string 2)) + (unless (string-equal "def" (match-string 1)) + (setq mlist (list mname) mname nil)) + (goto-char (match-beginning 1)) + (setq indent (current-column)) + (beginning-of-line))) + ;; nest class/module + (while (and (> indent 0) + (re-search-backward + (concat + "^[ \t]*\\(class\\|module\\)[ \t]+" + "\\([A-Z]" ruby-symbol-re "*\\)") + nil t)) + (goto-char (match-beginning 1)) + (if (< (current-column) indent) + (progn + (setq mlist (cons (match-string 2) mlist)) + (setq indent (current-column)) + (beginning-of-line)))) + (when mname + (let ((mn (split-string mname "\\.\\|::"))) + (if (cdr mn) + (progn + (cond + ((string-equal "" (car mn)) + (setq mn (cdr mn) mlist nil)) + ((string-equal "self" (car mn)) + (setq mn (cdr mn))) + ((let ((ml (nreverse mlist))) + (while ml + (if (string-equal (car ml) (car mn)) + (setq mlist (nreverse (cdr ml)) ml nil)) + (or (setq ml (cdr ml)) (nreverse mlist)))))) + (if mlist + (setcdr (last mlist) mn) + (setq mlist mn)) + (setq mn (last mn 2)) + (setq mname (concat "." (cadr mn))) + (setcdr mn nil)) + (setq mname (concat "#" mname))))) + ;; generate string + (if (consp mlist) + (setq mlist (mapconcat (function identity) mlist "::"))) + (if mname + (if mlist (concat mlist mname) mname) + mlist))))) + +(defun ruby-brace-to-do-end () + (when (looking-at "{") + (let ((orig (point)) (end (progn (ruby-forward-sexp) (point))) + oneline (end (make-marker))) + (setq oneline (and (eolp) (<= (point-at-bol) orig))) + (when (eq (char-before) ?\}) + (delete-char -1) + (cond + (oneline + (insert "\n") + (set-marker end (point))) + ((eq (char-syntax (preceding-char)) ?w) + (insert " "))) + (insert "end") + (if (eq (char-syntax (following-char)) ?w) + (insert " ")) + (goto-char orig) + (delete-char 1) + (if (eq (char-syntax (preceding-char)) ?w) + (insert " ")) + (insert "do") + (when (looking-at "\\sw\\||") + (insert " ") + (backward-char)) + (when oneline + (setq orig (point)) + (when (cond + ((looking-at "\\s *|") + (goto-char (match-end 0)) + (and (search-forward "|" (point-at-eol) 'move) + (not (eolp)))) + (t)) + (while (progn + (insert "\n") + (ruby-forward-sexp) + (looking-at "\\s *;\\s *")) + (delete-char (- (match-end 0) (match-beginning 0)))) + (goto-char orig) + (beginning-of-line 2) + (indent-region (point) end)) + (goto-char orig)) + t)))) + +(defun ruby-do-end-to-brace () + (when (and (or (bolp) + (not (memq (char-syntax (preceding-char)) '(?w ?_)))) + (looking-at "\\<do\\(\\s \\|$\\)")) + (let ((orig (point)) (end (progn (ruby-forward-sexp) (point))) + first last) + (backward-char 3) + (when (looking-at ruby-block-end-re) + (delete-char 3) + (insert "}") + (setq last (and (eolp) + (progn (backward-char 1) + (skip-syntax-backward " ") + (bolp)) + (1- (point-at-eol -1)))) + (goto-char orig) + (delete-char 2) + (insert "{") + (setq orig (point)) + (when (and last (<= last (point)) + (not (search-forward "#" (setq first (point-at-eol)) t))) + (goto-char (- end 4)) + (end-of-line 0) + (if (looking-at "\n\\s *") + (delete-char (- (match-end 0) (match-beginning 0))) t) + (goto-char first) + (if (looking-at "\n\\s *") + (delete-char (- (match-end 0) (match-beginning 0))) t)) + (goto-char orig) + (if (looking-at "\\s +|") + (delete-char (- (match-end 0) (match-beginning 0) 1))) + t)))) + +(defun ruby-toggle-block () + (interactive) + (or (ruby-brace-to-do-end) + (ruby-do-end-to-brace))) + +(eval-when-compile + (if (featurep 'font-lock) + (defmacro eval-when-font-lock-available (&rest args) (cons 'progn args)) + (defmacro eval-when-font-lock-available (&rest args)))) + +(eval-when-compile + (if (featurep 'hilit19) + (defmacro eval-when-hilit19-available (&rest args) (cons 'progn args)) + (defmacro eval-when-hilit19-available (&rest args)))) + +(eval-when-font-lock-available + (or (boundp 'font-lock-variable-name-face) + (setq font-lock-variable-name-face font-lock-type-face)) + + (defconst ruby-font-lock-syntactic-keywords + `( + ;; #{ }, #$hoge, #@foo are not comments + ("\\(#\\)[{$@]" 1 (1 . nil)) + ;; the last $', $", $` in the respective string is not variable + ;; the last ?', ?", ?` in the respective string is not ascii code + ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" + (2 (7 . nil)) + (4 (7 . nil))) + ;; $' $" $` .... are variables + ;; ?' ?" ?` are ascii codes + ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil)) + ;; regexps + ("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" + (4 (7 . ?/)) + (6 (7 . ?/))) + ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil)) + ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil)) + (,(concat ruby-here-doc-beg-re ".*\\(\n\\)") + ,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re)) + (ruby-here-doc-beg-syntax)) + (,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax)))) + + (unless (functionp 'syntax-ppss) + (defun syntax-ppss (&optional pos) + (parse-partial-sexp (point-min) (or pos (point))))) + + (defun ruby-in-ppss-context-p (context &optional ppss) + (let ((ppss (or ppss (syntax-ppss (point))))) + (if (cond + ((eq context 'anything) + (or (nth 3 ppss) + (nth 4 ppss))) + ((eq context 'string) + (nth 3 ppss)) + ((eq context 'heredoc) + (and (nth 3 ppss) + ;; If it's generic string, it's a heredoc and we don't care + ;; See `parse-partial-sexp' + (not (numberp (nth 3 ppss))))) + ((eq context 'non-heredoc) + (and (ruby-in-ppss-context-p 'anything) + (not (ruby-in-ppss-context-p 'heredoc)))) + ((eq context 'comment) + (nth 4 ppss)) + (t + (error (concat + "Internal error on `ruby-in-ppss-context-p': " + "context name `" (symbol-name context) "' is unknown")))) + t))) + + (defun ruby-in-here-doc-p () + (save-excursion + (let ((old-point (point)) (case-fold-search nil)) + (beginning-of-line) + (catch 'found-beg + (while (and (re-search-backward ruby-here-doc-beg-re nil t) + (not (ruby-singleton-class-p))) + (if (not (or (ruby-in-ppss-context-p 'anything) + (ruby-here-doc-find-end old-point))) + (throw 'found-beg t))))))) + + (defun ruby-here-doc-find-end (&optional limit) + "Expects the point to be on a line with one or more heredoc +openers. Returns the buffer position at which all heredocs on the +line are terminated, or nil if they aren't terminated before the +buffer position `limit' or the end of the buffer." + (save-excursion + (beginning-of-line) + (catch 'done + (let ((eol (save-excursion (end-of-line) (point))) + (case-fold-search nil) + ;; Fake match data such that (match-end 0) is at eol + (end-match-data (progn (looking-at ".*$") (match-data))) + beg-match-data end-re) + (while (re-search-forward ruby-here-doc-beg-re eol t) + (setq beg-match-data (match-data)) + (setq end-re (ruby-here-doc-end-match)) + + (set-match-data end-match-data) + (goto-char (match-end 0)) + (unless (re-search-forward end-re limit t) (throw 'done nil)) + (setq end-match-data (match-data)) + + (set-match-data beg-match-data) + (goto-char (match-end 0))) + (set-match-data end-match-data) + (goto-char (match-end 0)) + (point))))) + + (defun ruby-here-doc-beg-syntax () + (save-excursion + (goto-char (match-beginning 0)) + (unless (or (ruby-in-ppss-context-p 'non-heredoc) + (ruby-in-here-doc-p)) + (string-to-syntax "|")))) + + (defun ruby-here-doc-end-syntax () + (let ((pss (syntax-ppss)) (case-fold-search nil)) + (when (ruby-in-ppss-context-p 'heredoc pss) + (save-excursion + (goto-char (nth 8 pss)) ; Go to the beginning of heredoc. + (let ((eol (point))) + (beginning-of-line) + (if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line... + (not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment... + (progn (goto-char (match-end 0)) ; And it's the last heredoc on its line... + (not (re-search-forward ruby-here-doc-beg-re eol t)))) + (string-to-syntax "|"))))))) + + (eval-when-compile + (put 'ruby-mode 'font-lock-defaults + '((ruby-font-lock-keywords) + nil nil nil + beginning-of-line + (font-lock-syntactic-keywords + . ruby-font-lock-syntactic-keywords)))) + + (defun ruby-font-lock-docs (limit) + (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t) + (let (beg) + (beginning-of-line) + (setq beg (point)) + (forward-line 1) + (if (re-search-forward "^=end\\(\\s \\|$\\)" limit t) + (progn + (set-match-data (list beg (point))) + t))))) + + (defun ruby-font-lock-maybe-docs (limit) + (let (beg) + (save-excursion + (if (and (re-search-backward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t) + (string= (match-string 1) "begin")) + (progn + (beginning-of-line) + (setq beg (point))))) + (if (and beg (and (re-search-forward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t) + (string= (match-string 1) "end"))) + (progn + (set-match-data (list beg (point))) + t) + nil))) + + (defvar ruby-font-lock-syntax-table + (let* ((tbl (copy-syntax-table ruby-mode-syntax-table))) + (modify-syntax-entry ?_ "w" tbl) + tbl)) + + (defconst ruby-font-lock-keywords + (list + ;; functions + '("^\\s *def\\s +\\([^( \t\n]+\\)" + 1 font-lock-function-name-face) + ;; keywords + (cons (concat + "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\_<\\(defined\\?\\|" + (regexp-opt + '("alias" + "and" + "begin" + "break" + "case" + "catch" + "class" + "def" + "do" + "elsif" + "else" + "fail" + "ensure" + "for" + "end" + "if" + "in" + "module" + "next" + "not" + "or" + "raise" + "redo" + "rescue" + "retry" + "return" + "then" + "throw" + "super" + "unless" + "undef" + "until" + "when" + "while" + "yield" + ) + t) + "\\)" + ruby-keyword-end-re) + 2) + ;; here-doc beginnings + (list ruby-here-doc-beg-re 0 'font-lock-string-face) + ;; variables + '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\_<\\(nil\\|self\\|true\\|false\\)\\>" + 2 font-lock-variable-name-face) + ;; variables + '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W" + 1 font-lock-variable-name-face) + '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+" + 0 font-lock-variable-name-face) + ;; embedded document + '(ruby-font-lock-docs + 0 font-lock-comment-face t) + '(ruby-font-lock-maybe-docs + 0 font-lock-comment-face t) + ;; general delimited string + '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)" + (2 font-lock-string-face)) + ;; constants + '("\\(^\\|[^_]\\)\\_<\\([A-Z]+\\(\\w\\|_\\)*\\)" + 2 font-lock-type-face) + ;; symbols + '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)" + 2 font-lock-reference-face) + '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face) + ;; expression expansion + '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)" + 0 font-lock-variable-name-face t) + ;; warn lower camel case + ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" + ; 0 font-lock-warning-face) + ) + "*Additional expressions to highlight in ruby mode.")) + +(eval-when-hilit19-available + (hilit-set-mode-patterns + 'ruby-mode + '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string) + ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string) + ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string) + ("^\\s *#.*$" nil comment) + ("[^$@?\\]\\(#[^$@{\n].*$\\)" 1 comment) + ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string) + ("^\\s *\\(require\\|load\\).*$" nil include) + ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl) + ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun) + ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\|yield\\)\\>\\([^_]\\|$\\)" 1 defun) + ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|catch\\|throw\\|self\\|nil\\)\\>\\([^_]\\|$\\)" 1 keyword) + ("\\$\\(.\\|\\sw+\\)" nil type) + ("[$@].[a-zA-Z_0-9]*" nil struct) + ("^__END__" nil label)))) + + +;;;###autoload +(defun ruby-mode () + "Major mode for editing ruby scripts. +\\[ruby-indent-command] properly indents subexpressions of multi-line +class, module, def, if, while, for, do, and case statements, taking +nesting into account. + +The variable ruby-indent-level controls the amount of indentation. +\\{ruby-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map ruby-mode-map) + (setq mode-name "Ruby") + (setq major-mode 'ruby-mode) + (ruby-mode-variables) + + (make-local-variable 'imenu-create-index-function) + (setq imenu-create-index-function 'ruby-imenu-create-index) + + (make-local-variable 'add-log-current-defun-function) + (setq add-log-current-defun-function 'ruby-add-log-current-method) + + (add-hook + (cond ((boundp 'before-save-hook) + (make-local-variable 'before-save-hook) + 'before-save-hook) + ((boundp 'write-contents-functions) 'write-contents-functions) + ((boundp 'write-contents-hooks) 'write-contents-hooks)) + 'ruby-mode-set-encoding) + + (set (make-local-variable 'font-lock-defaults) '((ruby-font-lock-keywords) nil nil)) + (set (make-local-variable 'font-lock-keywords) ruby-font-lock-keywords) + (set (make-local-variable 'font-lock-syntax-table) ruby-font-lock-syntax-table) + (set (make-local-variable 'font-lock-syntactic-keywords) ruby-font-lock-syntactic-keywords) + + (if (fboundp 'run-mode-hooks) + (run-mode-hooks 'ruby-mode-hook) + (run-hooks 'ruby-mode-hook))) + +(provide 'ruby-mode) diff --git a/jni/ruby/misc/ruby-style.el b/jni/ruby/misc/ruby-style.el new file mode 100644 index 0000000..aca6d38 --- /dev/null +++ b/jni/ruby/misc/ruby-style.el @@ -0,0 +1,79 @@ +;;; -*- emacs-lisp -*- +;;; +;;; ruby-style.el - +;;; +;;; C/C++ mode style for Ruby. +;;; +;;; $Author: knu $ +;;; created at: Thu Apr 26 13:54:01 JST 2007 +;;; +;;; To switch to the "ruby" style automatically if it looks like a +;;; source file of ruby, add ruby-style-c-mode to c-mode-hook: +;;; +;;; (require 'ruby-style) +;;; (add-hook 'c-mode-hook 'ruby-style-c-mode) +;;; (add-hook 'c++-mode-hook 'ruby-style-c-mode) +;;; +;;; Customize the c-default-style variable to set the default style +;;; for each CC major mode. + +(defconst ruby-style-revision "$Revision: 42804 $" + "Ruby style revision string.") + +(defconst ruby-style-version + (and + (string-match "[0-9.]+" ruby-style-revision) + (substring ruby-style-revision (match-beginning 0) (match-end 0))) + "Ruby style version number.") + +(defun ruby-style-case-indent (x) + (save-excursion + (back-to-indentation) + (unless (progn (backward-up-list) (back-to-indentation) + (> (point) (cdr x))) + (goto-char (cdr x)) + (if (looking-at "\\<case\\|default\\>") '*)))) + +(defun ruby-style-label-indent (x) + (save-excursion + (back-to-indentation) + (unless (progn (backward-up-list) (back-to-indentation) + (>= (point) (cdr x))) + (goto-char (cdr x)) + (condition-case () + (progn + (backward-up-list) + (backward-sexp 2) + (if (looking-at "\\<switch\\>") '/)) + (error))))) + +(require 'cc-styles) +(c-add-style + "ruby" + '("bsd" + (c-basic-offset . 4) + (tab-width . 8) + (indent-tabs-mode . t) + (setq show-trailing-whitespace t) + (c-offsets-alist + (case-label . *) + (label . (ruby-style-label-indent *)) + (statement-case-intro . *) + (statement-case-open . *) + (statement-block-intro . (ruby-style-case-indent +)) + (access-label /) + ))) + +;;;###autoload +(defun ruby-style-c-mode () + (interactive) + (if (or (let ((name (buffer-file-name))) (and name (string-match "/ruby\\>" name))) + (save-excursion + (goto-char (point-min)) + (let ((head (progn (forward-line 100) (point))) + (case-fold-search nil)) + (goto-char (point-min)) + (re-search-forward "Copyright (C) .* Yukihiro Matsumoto" head t)))) + (c-set-style "ruby"))) + +(provide 'ruby-style) diff --git a/jni/ruby/misc/rubydb2x.el b/jni/ruby/misc/rubydb2x.el new file mode 100644 index 0000000..a74265f --- /dev/null +++ b/jni/ruby/misc/rubydb2x.el @@ -0,0 +1,104 @@ +(require 'gud) +(provide 'rubydb) + +;; ====================================================================== +;; rubydb functions + +;;; History of argument lists passed to rubydb. +(defvar gud-rubydb-history nil) + +(defun gud-rubydb-massage-args (file args) + (cons "-I" (cons "." (cons "-r" (cons "debug" (cons file args)))))) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defvar gud-rubydb-marker-acc "") + +(defun gud-rubydb-marker-filter (string) + (save-match-data + (setq gud-marker-acc (concat gud-marker-acc string)) + (let ((output "")) + + ;; Process all the complete markers in this chunk. + (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" + gud-marker-acc) + (setq + + ;; Extract the frame position from the marker. + gud-last-frame + (cons (substring gud-marker-acc (match-beginning 1) (match-end 1)) + (string-to-int (substring gud-marker-acc + (match-beginning 2) + (match-end 2)))) + + ;; Append any text before the marker to the output we're going + ;; to return - we don't include the marker in this text. + output (concat output + (substring gud-marker-acc 0 (match-beginning 0))) + + ;; Set the accumulator to the remaining text. + gud-marker-acc (substring gud-marker-acc (match-end 0)))) + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; gud-marker-acc until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + (if (string-match "\032.*\\'" gud-marker-acc) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring gud-marker-acc + 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq gud-marker-acc + (substring gud-marker-acc (match-beginning 0)))) + + (setq output (concat output gud-marker-acc) + gud-marker-acc "")) + + output))) + +(defun gud-rubydb-find-file (f) + (find-file-noselect f)) + +(defvar rubydb-command-name "ruby" + "File name for executing ruby.") + +;;;###autoload +(defun rubydb (command-line) + "Run rubydb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run rubydb (like this): " + (if (consp gud-rubydb-history) + (car gud-rubydb-history) + (concat rubydb-command-name " ")) + nil nil + '(gud-rubydb-history . 1)))) + + (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args) + (gud-marker-filter . gud-rubydb-marker-filter) + (gud-find-file . gud-rubydb-find-file) + )) + (gud-common-init command-line) + + (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") +; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "s" "\C-s" "Step one source line with display.") + (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "c" "\C-r" "Continue with display.") + (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") + (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") + (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") + (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") + + (setq comint-prompt-regexp "^(rdb:-) ") + (setq paragraph-start comint-prompt-regexp) + (run-hooks 'rubydb-mode-hook) + ) diff --git a/jni/ruby/misc/rubydb3x.el b/jni/ruby/misc/rubydb3x.el new file mode 100644 index 0000000..9d6bc57 --- /dev/null +++ b/jni/ruby/misc/rubydb3x.el @@ -0,0 +1,115 @@ +(require 'gud) +(provide 'rubydb) + +;; ====================================================================== +;; rubydb functions + +;;; History of argument lists passed to rubydb. +(defvar gud-rubydb-history nil) + +(if (fboundp 'gud-overload-functions) + (defun gud-rubydb-massage-args (file args) + (cons "-r" (cons "debug" (cons file args)))) + (defun gud-rubydb-massage-args (file args) + (cons "-r" (cons "debug" args)))) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defvar gud-rubydb-marker-acc "") +(make-variable-buffer-local 'gud-rubydb-marker-acc) + +(defun gud-rubydb-marker-filter (string) + (setq gud-rubydb-marker-acc (concat gud-rubydb-marker-acc string)) + (let ((output "")) + + ;; Process all the complete markers in this chunk. + (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n" + gud-rubydb-marker-acc) + (setq + + ;; Extract the frame position from the marker. + gud-last-frame + (cons (substring gud-rubydb-marker-acc (match-beginning 1) (match-end 1)) + (string-to-int (substring gud-rubydb-marker-acc + (match-beginning 2) + (match-end 2)))) + + ;; Append any text before the marker to the output we're going + ;; to return - we don't include the marker in this text. + output (concat output + (substring gud-rubydb-marker-acc 0 (match-beginning 0))) + + ;; Set the accumulator to the remaining text. + gud-rubydb-marker-acc (substring gud-rubydb-marker-acc (match-end 0)))) + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; gud-rubydb-marker-acc until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + (if (string-match "\032.*\\'" gud-rubydb-marker-acc) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring gud-rubydb-marker-acc + 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq gud-rubydb-marker-acc + (substring gud-rubydb-marker-acc (match-beginning 0)))) + + (setq output (concat output gud-rubydb-marker-acc) + gud-rubydb-marker-acc "")) + + output)) + +(defun gud-rubydb-find-file (f) + (save-excursion + (let ((buf (find-file-noselect f))) + (set-buffer buf) +;; (gud-make-debug-menu) + buf))) + +(defvar rubydb-command-name "ruby" + "File name for executing ruby.") + +;;;###autoload +(defun rubydb (command-line) + "Run rubydb on program FILE in buffer *gud-FILE*. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run rubydb (like this): " + (if (consp gud-rubydb-history) + (car gud-rubydb-history) + (concat rubydb-command-name " ")) + nil nil + '(gud-rubydb-history . 1)))) + + (if (not (fboundp 'gud-overload-functions)) + (gud-common-init command-line 'gud-rubydb-massage-args + 'gud-rubydb-marker-filter 'gud-rubydb-find-file) + (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args) + (gud-marker-filter . gud-rubydb-marker-filter) + (gud-find-file . gud-rubydb-find-file))) + (gud-common-init command-line rubydb-command-name)) + + (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.") +; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "s" "\C-s" "Step one source line with display.") + (gud-def gud-next "n" "\C-n" "Step one line (skip functions).") + (gud-def gud-cont "c" "\C-r" "Continue with display.") + (gud-def gud-finish "finish" "\C-f" "Finish executing current function.") + (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).") + (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).") + (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.") + + (setq comint-prompt-regexp "^(rdb:-) ") + (if (boundp 'comint-last-output-start) + (set-marker comint-last-output-start (point))) + (set (make-local-variable 'paragraph-start) comint-prompt-regexp) + (run-hooks 'rubydb-mode-hook) + ) |