384 lines
13 KiB
EmacsLisp
384 lines
13 KiB
EmacsLisp
|
;;; 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
|