my-emacs-d/elpa/electric-case-20150417.412/electric-case.el

384 lines
13 KiB
EmacsLisp
Raw Normal View History

;;; electric-case.el --- insert camelCase, snake_case words without "Shift"ing
;; Copyright (C) 2013-2015 zk_phi
;; 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 2 of the License, 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 this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
;; Version: 2.2.2
;; Package-Version: 20150417.412
;; Author: zk_phi
;; URL: http://hins11.yu-yake.com/
;;; Commentary:
;; Load this script
;;
;; (require 'electric-case)
;;
;; and initialize in major-mode hooks.
;;
;; (add-hook 'java-mode-hook 'electric-case-java-init)
;;
;; And when you type the following in java-mode for example,
;;
;; public class test-class{
;; public void test-method(void){
;;
;; =electric-case= automatically converts it into :
;;
;; public class TestClass{
;; public void testMethod(void){
;;
;; Preconfigured settings for some other languages are also
;; provided. Try:
;;
;; (add-hook 'c-mode-hook electric-case-c-init)
;; (add-hook 'ahk-mode-hook electric-case-ahk-init)
;; (add-hook 'scala-mode-hook electric-case-scala-init)
;;
;; For more informations, see Readme.org.
;;; Change Log:
;; 1.0.0 first released
;; 1.0.1 fixed java settings
;; 1.0.2 minor fixes
;; 1.0.3 fixed java settings
;; 1.0.4 fixed java settings
;; 1.0.5 fixed C settings
;; 1.1.0 added electric-case-convert-calls
;; 1.1.1 modified arguments for criteria function
;; 1.1.2 added ahk-mode settings
;; 1.1.3 added scala-mode settings, and refactord
;; 1.1.4 fixes and improvements
;; 2.0.0 added pending-overlays
;; 2.0.1 added electric-case-trigger to post-command-hook
;; deleted variable "convert-calls"
;; 2.0.2 minow fixes for criterias
;; 2.0.3 removed electric-case-trigger from post-command-hook
;; 2.0.4 fixed trigger and added hook again
;; 2.1.0 added 2 custom variables, minor fixes
;; 2.1.1 added 2 custom variables
;; 2.2.0 changed behavior
;; now only symbols overlayd are converted
;; 2.2.1 fixed bug that words without overlay may converted
;; 2.2.2 fixed bug that electric-case-convert-end is ignored
;;; Code:
(eval-when-compile (require 'cl))
;; * constants
(defconst electric-case-version "2.2.2")
;; * customs
(defgroup electric-case nil
"Insert camelCase, snake_case words without \"Shift\"ing"
:group 'emacs)
(defcustom electric-case-pending-overlay 'shadow
"Face used to highlight pending symbols"
:group 'electric-case)
(defcustom electric-case-convert-calls nil
"When nil, only declarations are converted."
:group 'electric-case)
(defcustom electric-case-convert-nums nil
"When non-nil, hyphens around numbers are also counted as a
part of the symbol."
:group 'electric-case)
(defcustom electric-case-convert-beginning nil
"When non-nil, hyphens at the beginning of symbols are also
counted as a part of the symbol."
:group 'electric-case)
(defcustom electric-case-convert-end nil
"When non-nil, hyphens at the end of symbols are also counted
as a part of the symbol."
:group 'electric-case)
;; * mode variables
(define-minor-mode electric-case-mode
"insert camelCase, snake_case words without \"Shift\"ing"
:init-value nil
:lighter "eCase"
:global nil
(if electric-case-mode
(add-hook 'post-command-hook 'electric-case--post-command-function nil t)
(remove-hook 'post-command-hook 'electric-case--post-command-function t)))
;; * buffer-local variables
(defvar electric-case-criteria (lambda (b e) 'camel))
(make-variable-buffer-local 'electric-case-criteria)
(defvar electric-case-max-iteration 1)
(make-variable-buffer-local 'electric-case-max-iteration)
;; * utilities
;; ** motion
(defun electric-case--range (n)
(save-excursion
(let* ((pos (point))
(beg (ignore-errors
(dotimes (_ n)
(when (bobp) (error "beginning of buffer"))
(backward-word)
(if electric-case-convert-nums
(skip-chars-backward "[:alnum:]-")
(skip-chars-backward "[:alpha:]-"))
(unless electric-case-convert-beginning
(skip-chars-forward "-")))
(point)))
(end (when beg
(goto-char beg)
(if electric-case-convert-nums
(skip-chars-forward "[:alnum:]-")
(skip-chars-forward "[:alpha:]-"))
(unless electric-case-convert-end
(skip-chars-backward "-"))
(point))))
;; inside-lo|ng-symbol => nil
;; b p e
(when (and end (<= end pos))
(cons beg end)))))
;; ** replace buffer
(defun electric-case--replace-buffer (beg end str)
"(replace 1 2 \"aa\")
buffer-string => aaffer-string"
(when (not (string= (buffer-substring-no-properties beg end) str))
(let ((pos (point))
(oldlen (- end beg))
(newlen (length str)))
(kill-region beg end)
(goto-char beg)
(insert str)
(remove-overlays beg (+ beg newlen))
(goto-char (+ pos (- newlen oldlen))))))
;; ** overlay management
(defvar electric-case--overlays nil)
(make-variable-buffer-local 'electric-case--overlays)
(defun electric-case--put-overlay (n)
(let ((range (electric-case--range n)))
(when range
(let ((ov (make-overlay (car range) (cdr range))))
(overlay-put ov 'face electric-case-pending-overlay)
(add-to-list 'electric-case--overlays ov)))))
(defun electric-case--remove-overlays ()
(mapc 'delete-overlay electric-case--overlays)
(setq electric-case--overlays nil))
(defun electric-case--not-on-overlay-p ()
(let ((res t) (pos (point)))
(dolist (ov electric-case--overlays res)
(setq res (and res
(or (< pos (overlay-start ov))
(< (overlay-end ov) pos)))))))
;; * commands
(defun electric-case--convert-all ()
(dolist (ov electric-case--overlays)
(let ((beg (overlay-start ov))
(end (overlay-end ov)))
;; vvv i dont remember why i added whis line vvv
(when (string-match "[a-z]" (buffer-substring-no-properties beg end))
(let* ((type (apply electric-case-criteria (list beg end)))
(str (buffer-substring-no-properties beg end))
(wlst (split-string str "-"))
(convstr (case type
('ucamel (mapconcat (lambda (w) (upcase-initials w)) wlst ""))
('camel (concat
(car wlst)
(mapconcat (lambda (w) (upcase-initials w)) (cdr wlst) "")))
('usnake (mapconcat (lambda (w) (upcase w)) wlst "_"))
('snake (mapconcat 'identity wlst "_"))
(t nil))))
(when convstr
(electric-case--replace-buffer beg end convstr))))))
(electric-case--remove-overlays))
(defun electric-case--post-command-function ()
;; update overlay
(when (and (eq 'self-insert-command (key-binding (this-single-command-keys)))
(characterp last-command-event)
(string-match
(if electric-case-convert-nums "[a-zA-Z0-9]" "[a-zA-Z]")
(char-to-string last-command-event)))
(electric-case--remove-overlays)
(let (n)
(dotimes (n electric-case-max-iteration)
(electric-case--put-overlay (- electric-case-max-iteration n)))))
;; electric-case trigger
(when (and (electric-case--not-on-overlay-p)
(not mark-active))
(electric-case--convert-all)))
;; * settings
;; ** utilities
(defun electric-case--possible-properties (beg end)
(let* ((ret (point))
(str (buffer-substring beg end))
(convstr (replace-regexp-in-string "-" "" str))
(val (progn (electric-case--replace-buffer beg end convstr)
(font-lock-fontify-buffer)
(sit-for 0)
(text-properties-at beg))))
(electric-case--replace-buffer beg (+ beg (length convstr)) str)
(font-lock-fontify-buffer)
val))
(defun electric-case--this-line-string ()
(buffer-substring (save-excursion (beginning-of-line) (point))
(save-excursion (end-of-line) (point))))
;; ** c-mode
(defun electric-case-c-init ()
(electric-case-mode 1)
(setq electric-case-max-iteration 2)
(setq electric-case-criteria
(lambda (b e)
(let ((proper (electric-case--possible-properties b e))
(key (key-description (this-single-command-keys))))
(cond
((member 'font-lock-variable-name-face proper)
;; #ifdef A_MACRO / int variable_name;
(if (member '(cpp-macro) (c-guess-basic-syntax)) 'usnake 'snake))
((member 'font-lock-string-face proper) nil)
((member 'font-lock-comment-face proper) nil)
((member 'font-lock-keyword-face proper) nil)
((member 'font-lock-function-name-face proper) 'snake)
((member 'font-lock-type-face proper) 'snake)
(electric-case-convert-calls 'snake)
(t nil)))))
(defadvice electric-case-trigger (around electric-case-c-try-semi activate)
(when (and electric-case-mode
(eq major-mode 'c-mode))
(if (not (string= (key-description (this-single-command-keys)) ";"))
ad-do-it
(insert ";")
(backward-char)
ad-do-it
(delete-char 1))))
)
;; ** java-mode
(defconst electric-case-java-primitives
'("boolean" "char" "byte" "short" "int" "long" "float" "double" "void"))
(defun electric-case-java-init ()
(electric-case-mode 1)
(setq electric-case-max-iteration 2)
(setq electric-case-criteria
(lambda (b e)
;; do not convert primitives
(when (not (member (buffer-substring b e) electric-case-java-primitives))
(let ((proper (electric-case--possible-properties b e))
(str (electric-case--this-line-string)))
(cond
((string-match "^import" str)
;; import java.util.ArrayList;
(if (= (char-before) ?\;) 'ucamel nil))
;; annotation
((save-excursion (goto-char b)
(and (not (= (point) (point-min)))
(= (char-before) ?@)))
'camel)
((member 'font-lock-string-face proper) nil)
((member 'font-lock-comment-face proper) nil)
((member 'font-lock-keyword-face proper) nil)
((member 'font-lock-type-face proper) 'ucamel)
((member 'font-lock-function-name-face proper) 'camel)
((member 'font-lock-variable-name-face proper) 'camel)
(electric-case-convert-calls 'camel)
(t nil))))))
(defadvice electric-case-trigger (around electric-case-java-try-semi activate)
(when (and electric-case-mode
(eq major-mode 'java-mode))
(if (not (string= (key-description (this-single-command-keys)) ";"))
ad-do-it
(insert ";")
(backward-char)
ad-do-it
(delete-char 1))))
)
;; ** scala-mode
(defun electric-case-scala-init ()
(electric-case-mode 1)
(setq electric-case-max-iteration 2)
(setq electric-case-criteria
(lambda (b e)
(when (not (member (buffer-substring b e) electric-case-java-primitives))
(let ((proper (electric-case--possible-properties b e)))
(cond
((member 'font-lock-string-face proper) nil)
((member 'font-lock-comment-face proper) nil)
((member 'font-lock-keyword-face proper) nil)
((member 'font-lock-type-face proper) 'ucamel)
((member 'font-lock-function-name-face proper) 'camel)
((member 'font-lock-variable-name-face proper) 'camel)
(electric-case-convert-calls 'camel)
(t nil))))))
)
;; ** ahk-mode
(defun electric-case-ahk-init ()
(electric-case-mode 1)
(setq electric-case-max-iteration 1)
(setq electric-case-criteria
(lambda (b e)
(let ((proper (electric-case--possible-properties b e)))
(cond
((member 'font-lock-string-face proper) nil)
((member 'font-lock-comment-face proper) nil)
((member 'font-lock-keyword-face proper) 'ucamel)
(electric-case-convert-calls 'camel)
(t nil)))))
)
;; * provide
(provide 'electric-case)
;;; electric-case.el ends here