;;; emacs.el --- 10sr emacs initialization ;;; Commentary: ;;; Code: ;; SETUP_LOAD: (let ((file "DOTFILES_DIR/emacs.el")) ;; SETUP_LOAD: (and (file-readable-p file) ;; SETUP_LOAD: (load-file file))) (setq debug-on-error t) ;; make directories (unless (file-directory-p (expand-file-name user-emacs-directory)) (make-directory (expand-file-name user-emacs-directory))) (let ((d (expand-file-name (concat user-emacs-directory "lisp")))) (unless (file-directory-p d) (make-directory d)) (add-to-list 'load-path d)) (require 'cl-lib) (require 'simple) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Some macros for internals ;; `emacs --load emacs.el` with Emacs 24.3 requires with-eval-after-load to be ;; defined at the toplevel (means that it should not be defined inside of some ;; special forms like `when'. I do not now how to do with about this...) (unless (fboundp 'with-eval-after-load) ;; polyfill for Emacs < 24.4 (defmacro with-eval-after-load (file &rest body) "After FILE is loaded execute BODY." (declare (indent 1) (debug t)) `(eval-after-load ,file (quote (progn ,@body))))) (defun call-after-init (func) "If `after-init-hook' has been run, call FUNC immediately. Otherwize hook it." (if after-init-time (funcall func) (add-hook 'after-init-hook func))) (defmacro safe-require-or-eval (feature) "Require FEATURE if available. At compile time the feature will be loaded immediately." `(eval-and-compile (message "safe-require-or-eval: Trying to require %s" ,feature) (require ,feature nil t))) (defmacro autoload-eval-lazily (feature &optional functions &rest body) "Define autoloading FEATURE that defines FUNCTIONS. FEATURE is a symbol. FUNCTIONS is a list of symbols. If FUNCTIONS is nil, the function same as FEATURE is defined as autoloaded function. BODY is passed to `eval-after-load'. After this macro is expanded, this returns the path to library if FEATURE found, otherwise returns nil." (declare (indent 2) (debug t)) (let* ((libname (symbol-name (eval feature))) (libpath (locate-library libname))) `(progn (when (locate-library ,libname) ,@(mapcar (lambda (f) `(unless (fboundp ',f) (progn (message "Autoloaded function `%S' defined (%s)" (quote ,f) ,libpath) (autoload (quote ,f) ,libname ,(concat "Autoloaded function defined in \"" libpath "\".") t)))) (or (eval functions) `(,(eval feature))))) (eval-after-load ,feature (quote (progn ,@body))) (locate-library ,libname)))) (when (autoload-eval-lazily 'tetris nil (message "Tetris loaded!")) (message "Tetris found!")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; download library from web (defvar fetch-library-enabled-p t "Set nil to skip downloading with `fetch-library'.") (defun fetch-library (url &optional byte-compile-p force-download-p) "Download a library from URL and locate it in \"~/emacs.d/lisp/\". Return nil if library unfound and failed to download, otherwise the path where the library installed. If BYTE-COMPILE-P is t byte compile the file after downloading. If FORCE-DOWNLOAD-P it t ignore exisiting library and always download. This function also checks the value of `fetch-library-enabled-p' and do not fetch libraries if this value is nil. In this case all arguments (including FORCE-DOWNLOAD-P) will be ignored." (let* ((dir (expand-file-name (concat user-emacs-directory "lisp/"))) (lib (file-name-sans-extension (file-name-nondirectory url))) (lpath (concat dir lib ".el")) (locate-p (locate-library lib))) (if (and fetch-library-enabled-p (or force-download-p (not locate-p))) (if (progn (message "Downloading %s..." url) (download-file url lpath t)) (progn (message "Downloading %s...done" url) (when (and byte-compile-p (require 'bytecomp nil t)) (and (file-exists-p (byte-compile-dest-file lpath)) (delete-file (byte-compile-dest-file lpath))) (message "Byte-compiling %s..." lpath) (byte-compile-file lpath) (message "Byte-compiling %s...done" lpath))) (progn (and (file-writable-p lpath) (delete-file lpath)) (message "Downloading %s...failed" url)))) (locate-library lib))) ;; If EMACS_EL_DRY_RUN is set and it is not an empty string, fetch-library ;; does not actually fetch library. (let ((dryrun (getenv "EMACS_EL_DRY_RUN"))) (when (and dryrun (< 0 (length dryrun))) (setq fetch-library-enabled-p nil) (message "EMACS_EL_DRY_RUN is set. Skip fetching libraries."))) (defun download-file (url path &optional ok-if-already-exists) "Download file from URL and output to PATH. IF OK-IF-ALREADY-EXISTS is true force download." (let ((curl (executable-find "curl")) (wget (executable-find "wget"))) (cond (wget (if (and (not ok-if-already-exists) (file-exists-p path)) nil (and (eq 0 (call-process wget nil nil nil "-O" path url )) path))) (curl (if (and (not ok-if-already-exists) (file-exists-p path)) nil (and (eq 0 (call-process curl nil nil nil "--output" path "-L" url )) path))) (t (ignore-errors (require 'url) (url-copy-file url path ok-if-already-exists) path))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; package (set (defvar 10sr-package-list) '( markdown-mode yaml-mode gnuplot-mode php-mode erlang js2-mode git-commit gitignore-mode adoc-mode ;; ack color-moccur ggtags flycheck auto-highlight-symbol ;; is flymake installs are required? ;;flymake-jshint ;;flymake-python-pyflakes xclip foreign-regexp multi-term term-run editorconfig git-ps1-mode restart-emacs fill-column-indicator pkgbuild-mode minibuffer-line scala-mode2 ensime editorconfig cyberpunk-theme git-command prompt-text ;; 10sr repository ;; 10sr-extras terminal-title recentf-show dired-list-all-mode pack set-modeline-color read-only-only-mode smart-revert autosave ;;window-organizer remember-major-modes-mode ilookup pasteboard )) (when (safe-require-or-eval 'package) (setq package-archives `(,@package-archives ("melpa" . "https://melpa.org/packages/") ("10sr-el" . "https://10sr.github.io/emacs-lisp/p/"))) (package-initialize) (defun my-auto-install-package () "Install packages semi-automatically." (interactive) (package-refresh-contents) (mapc (lambda (pkg) (or (package-installed-p pkg) (locate-library (symbol-name pkg)) (package-install pkg))) 10sr-package-list)) ) ;; (lazy-load-eval 'sudoku) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; my-idle-hook (defvar my-idle-hook nil "Hook run when idle for several secs.") (defvar my-idle-hook-sec 5 "Second to run `my-idle-hook'.") (run-with-idle-timer my-idle-hook-sec t (lambda () (run-hooks 'my-idle-hook))) ;; (add-hook 'my-idle-hook ;; (lambda () ;; (message "idle hook message"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; start and quit (setq inhibit-startup-message t) (setq confirm-kill-emacs 'y-or-n-p) (setq gc-cons-threshold (* 1024 1024 4)) (when window-system (add-to-list 'default-frame-alist '(cursor-type . box)) (add-to-list 'default-frame-alist '(background-color . "white")) (add-to-list 'default-frame-alist '(foreground-color . "gray10")) ;; (add-to-list 'default-frame-alist '(alpha . (80 100 100 100))) ;; does not work? ) ;; (add-to-list 'default-frame-alist '(cursor-type . box)) (if window-system (menu-bar-mode 1) (menu-bar-mode 0)) (and (fboundp 'tool-bar-mode) (tool-bar-mode 0)) (and (fboundp 'set-scroll-bar-mode) (set-scroll-bar-mode nil)) (add-hook 'kill-emacs-hook ;; load init file when terminating emacs to ensure file is not broken 'reload-init-file) (defun my-force-kill-emacs () "My force kill Emacs." (interactive) (let ((kill-emacs-hook nil)) (kill-emacs))) (call-after-init (lambda () (message "%s %s" invocation-name emacs-version) (message "Invocation directory: %s" default-directory) (message "%s was taken to initialize emacs." (emacs-init-time)) (switch-to-buffer "*Messages*"))) (cd ".") ; when using windows use / instead of \ in `default-directory' ;; locale (set-language-environment "Japanese") (set-default-coding-systems 'utf-8-unix) (prefer-coding-system 'utf-8-unix) (setq system-time-locale "C") ;; my prefix map (defvar my-prefix-map nil "My prefix map.") (define-prefix-command 'my-prefix-map) (define-key ctl-x-map (kbd "C-x") 'my-prefix-map) (define-key my-prefix-map (kbd "C-q") 'quoted-insert) (define-key my-prefix-map (kbd "C-z") 'suspend-frame) ;; (comint-show-maximum-output) ;; kill scratch (call-after-init (lambda () (let ((buf (get-buffer "*scratch*"))) (when buf (kill-buffer buf))))) ;; modifier keys ;; (setq mac-option-modifier 'control) ;; display (setq visible-bell t) (setq ring-bell-function 'ignore) (mouse-avoidance-mode 'banish) (setq echo-keystrokes 0.1) (defun reload-init-file () "Reload Emacs init file." (interactive) (when (and user-init-file (file-readable-p user-init-file)) (load-file user-init-file))) (safe-require-or-eval 'session) ;; server (set-variable 'server-name (concat "server" (number-to-string (emacs-pid)))) ;; In Cygwin Environment `server-runnning-p' stops when server-use-tcp is nil ;; In Darwin environment, init fails with message like 'Service name too long' ;; when server-use-tcp is nil (when (or (eq system-type 'cygwin) (eq system-type 'darwin)) (set-variable 'server-use-tcp t)) ;; MSYS2 fix (when (eq system-type 'windows-nt) (setq shell-file-name (executable-find "bash")) '(setq function-key-map `(,@function-key-map ([pause] . [?\C-c]) )) (define-key key-translation-map (kbd "") (kbd "C-c")) '(keyboard-translate [pause] (kbd "C-c")p) ;; TODO: move to other place later (when (not window-system) (setq interprogram-paste-function nil) (setq interprogram-cut-function nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; global keys (global-set-key (kbd "") 'scroll-down-line) (global-set-key (kbd "") 'scroll-up-line) (global-set-key (kbd "") 'scroll-down) (global-set-key (kbd "") 'scroll-up) ;; (define-key my-prefix-map (kbd "C-h") help-map) (global-set-key (kbd "C-\\") help-map) (define-key ctl-x-map (kbd "DEL") help-map) (define-key ctl-x-map (kbd "C-h") help-map) (define-key help-map "a" 'apropos) ;; disable annoying keys (global-set-key [prior] 'ignore) (global-set-key (kbd "") 'ignore) (global-set-key [menu] 'ignore) (global-set-key [down-mouse-1] 'ignore) (global-set-key [down-mouse-2] 'ignore) (global-set-key [down-mouse-3] 'ignore) (global-set-key [mouse-1] 'ignore) (global-set-key [mouse-2] 'ignore) (global-set-key [mouse-3] 'ignore) (global-set-key (kbd "") 'ignore) (global-set-key (kbd "C-") 'ignore) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; editting (defun my-copy-whole-line () "Copy whole line." (interactive) (kill-new (concat (buffer-substring (point-at-bol) (point-at-eol)) "\n"))) (setq require-final-newline t) (setq kill-whole-line t) (setq scroll-conservatively 35 scroll-margin 2 scroll-step 0) (setq-default major-mode 'text-mode) (setq next-line-add-newlines nil) (setq kill-read-only-ok t) (setq truncate-partial-width-windows nil) ; when splitted horizontally ;; (setq-default line-spacing 0.2) (setq-default indicate-empty-lines t) ; when using x indicate empty line (setq-default tab-width 4) (setq-default indent-tabs-mode nil) (setq-default indent-line-function nil) ;; (pc-selection-mode 1) ; make some already defined keybind back to default (delete-selection-mode 1) (cua-mode 0) (setq line-move-visual nil) ;; key bindings ;; moving around ;; (global-set-key (kbd "M-j") 'next-line) ;; (global-set-key (kbd "M-k") 'previous-line) ;; (global-set-key (kbd "M-h") 'backward-char) ;; (global-set-key (kbd "M-l") 'forward-char) ;;(keyboard-translate ?\M-j ?\C-j) ;; (global-set-key (kbd "M-p") 'backward-paragraph) (define-key esc-map "p" 'backward-paragraph) ;; (global-set-key (kbd "M-n") 'forward-paragraph) (define-key esc-map "n" 'forward-paragraph) (global-set-key (kbd "C-") 'scroll-down-line) (global-set-key (kbd "C-") 'scroll-up-line) (global-set-key (kbd "C-") 'scroll-down) (global-set-key (kbd "C-") 'scroll-up) (global-set-key (kbd "