;;; ruby-end.el --- Automatic insertion of end blocks for Ruby ;; Copyright (C) 2010 Johan Andersson ;; Author: Johan Andersson ;; Maintainer: Johan Andersson ;; Version: 0.1.0 ;; Keywords: speed, convenience ;; URL: http://github.com/rejeep/ruby-end ;; This file is NOT part of GNU Emacs. ;;; License: ;; This program 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, or (at your option) ;; any later version. ;; This program 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 GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; ruby-end is a minor mode for Emacs that can be used with ruby-mode ;; to automatically close blocks by inserting "end" when typing a ;; block-keyword, followed by a space. ;; ;; To use ruby-end-mode, make sure that this file is in Emacs load-path: ;; (add-to-list 'load-path "/path/to/directory/or/file") ;; ;; Then require ruby-end: ;; (require 'ruby-end) ;; ;; ruby-end-mode is automatically started in ruby-mode. ;;; Code: (defvar ruby-end-expand-key "SPC" "Space key name.") (defvar ruby-end-mode-map (let ((map (make-sparse-keymap)) (key (read-kbd-macro ruby-end-expand-key))) (define-key map key 'ruby-end-space) map) "Keymap for `ruby-end-mode'.") (defcustom ruby-end-check-statement-modifiers t "*Disable or enable expansion (insertion of end) for statement modifiers" :type 'boolean :group 'ruby) (defconst ruby-end-expand-postfix-modifiers-before-re "\\(?:if\\|unless\\|while\\)" "Regular expression matching statements before point.") (defconst ruby-end-expand-prefix-check-modifiers-re "^\\s-*" "Prefix for regular expression to prevent expansion with statement modifiers") (defconst ruby-end-expand-prefix-re "\\(?:^\\|\\s-+\\)" "Prefix for regular expression") (defconst ruby-end-expand-keywords-before-re "\\(?:^\\|\\s-+\\)\\(?:do\\|def\\|class\\|module\\|case\\|for\\|begin\\)" "Regular expression matching blocks before point.") (defconst ruby-end-expand-after-re "\\s-*$" "Regular expression matching after point.") (defun ruby-end-space () "Called when SPC-key is pressed." (interactive) (cond ((ruby-end-expand-p) (ruby-end-insert-end) (insert " ")) (t (let ((ruby-end-mode nil)) (call-interactively (key-binding (read-kbd-macro ruby-end-expand-key))))))) (defun ruby-end-insert-end () "Closes block by inserting end." (save-excursion (newline) (insert "end") (indent-according-to-mode))) (defun ruby-end-expand-p () "Checks if expansion (insertion of end) should be done." (let ((ruby-end-expand-statement-modifiers-before-re (concat (if ruby-end-check-statement-modifiers ruby-end-expand-prefix-check-modifiers-re ruby-end-expand-prefix-re) ruby-end-expand-postfix-modifiers-before-re))) (and (ruby-end-code-at-point-p) (or (looking-back ruby-end-expand-statement-modifiers-before-re) (looking-back ruby-end-expand-keywords-before-re)) (looking-at ruby-end-expand-after-re)))) (defun ruby-end-code-at-point-p () "Checks if point is code, or comment or string." (let ((properties (text-properties-at (point)))) (and (null (memq 'font-lock-string-face properties)) (null (memq 'font-lock-comment-face properties))))) ;;;###autoload (define-minor-mode ruby-end-mode "Automatic insertion of end blocks for Ruby." :init-value nil :lighter " end" :keymap ruby-end-mode-map) (add-hook 'ruby-mode-hook 'ruby-end-mode) (provide 'ruby-end) ;;; ruby-end.el ends here