;;; 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))) ;; 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) ;; (add-hook 'after-change-major-mode-hook ;; (lambda () ;; (message "cmm: %S %s" ;; major-mode ;; buffer-file-name))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Some macros for internals (unless (fboundp 'with-eval-after-load) ;; polyfill for Emacs < 24.4 (defmacro with-eval-after-load (file &rest body) "Execute BODY after FILE is loaded." (declare (indent 1)) `(eval-after-load ,file '(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 (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 erlang js2-mode git-commit gitignore-mode ;; ack color-moccur ggtags flycheck ;; 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 scala-mode2 ensime editorconfig git-command ;; 10sr repository 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 "%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) (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))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; title and mode-line (when (safe-require-or-eval 'terminal-title) ;; if TERM is not screen use default value (if (getenv "TMUX") ;; if use tmux locally just basename of current dir (set-variable 'terminal-title-format '((file-name-nondirectory (directory-file-name default-directory)))) (if (and (let ((tty-type (frame-parameter nil 'tty-type))) (and tty-type (equal (car (split-string tty-type "-")) "screen"))) (not (getenv "SSH_CONNECTION"))) (set-variable 'terminal-title-format '((file-name-nondirectory (directory-file-name default-directory)))) ;; seems that TMUX is used locally and ssh to remote host (set-variable 'terminal-title-format `("em:" ,user-login-name "@" ,(car (split-string system-name "\\.")) ":" default-directory)) ) ) (terminal-title-mode)) (setq eol-mnemonic-dos "\\r\\n") (setq eol-mnemonic-mac "\\r") (setq eol-mnemonic-unix "\\n") (which-function-mode 0) (line-number-mode 0) (column-number-mode 0) (size-indication-mode 0) (setq mode-line-position '(:eval (format "L%%l/%d,C%%c" (count-lines (point-max) (point-min))))) (when (safe-require-or-eval 'git-ps1-mode) (git-ps1-mode)) ;; http://www.geocities.jp/simizu_daisuke/bunkei-meadow.html#frame-title ;; display date (when (safe-require-or-eval 'time) (setq display-time-interval 29) (setq display-time-day-and-date t) (setq display-time-format "%a, %d %b %Y %T") (if window-system (display-time-mode 0) (display-time-mode 1)) (when display-time-mode (display-time-update))) ;; ;; current directory ;; (let ((ls (member 'mode-line-buffer-identification ;; mode-line-format))) ;; (setcdr ls ;; (cons '(:eval (concat " (" ;; (abbreviate-file-name default-directory) ;; ")")) ;; (cdr ls)))) ;; ;; display last modified time ;; (let ((ls (member 'mode-line-buffer-identification ;; mode-line-format))) ;; (setcdr ls ;; (cons '(:eval (concat " " ;; my-buffer-file-last-modified-time)) ;; (cdr ls)))) (defun buffer-list-not-start-with-space () "Return a list of buffers that not start with whitespaces." (let ((bl (buffer-list)) b nbl) (while bl (setq b (pop bl)) (unless (string-equal " " (substring (buffer-name b) 0 1)) (add-to-list 'nbl b))) nbl)) ;; http://www.masteringemacs.org/articles/2012/09/10/hiding-replacing-modeline-strings/ ;; (add-to-list 'minor-mode-alist ;; '(global-whitespace-mode "")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; minibuffer (setq insert-default-directory t) (setq completion-ignore-case t read-file-name-completion-ignore-case t read-buffer-completion-ignore-case t) (setq resize-mini-windows t) (temp-buffer-resize-mode 1) (savehist-mode 1) (fset 'yes-or-no-p 'y-or-n-p) ;; complete symbol when `eval' (define-key read-expression-map (kbd "TAB") 'completion-at-point) (define-key minibuffer-local-map (kbd "C-u") (lambda () (interactive) (delete-region (point-at-bol) (point)))) ;; I dont know these bindings are good (define-key minibuffer-local-map (kbd "C-p") (kbd "ESC p")) (define-key minibuffer-local-map (kbd "C-n") (kbd "ESC n")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; letters, font-lock mode and fonts ;; (set-face-background 'vertical-border (face-foreground 'mode-line)) ;; (set-window-margins (selected-window) 1 1) (and (or (eq system-type 'Darwin) (eq system-type 'darwin)) (fboundp 'mac-set-input-method-parameter) (mac-set-input-method-parameter 'japanese 'cursor-color "red") (mac-set-input-method-parameter 'roman 'cursor-color "black")) (when (and (boundp 'input-method-activate-hook) ; i dont know this is correct (boundp 'input-method-inactivate-hook)) (add-hook 'input-method-activate-hook (lambda () (set-cursor-color "red"))) (add-hook 'input-method-inactivate-hook (lambda () (set-cursor-color "black")))) (when (safe-require-or-eval 'paren) (show-paren-mode 1) (setq show-paren-delay 0.5 show-paren-style 'parenthesis) ; mixed is hard to read ;; (set-face-background 'show-paren-match ;; "black") ;; ;; (face-foreground 'default)) ;; (set-face-foreground 'show-paren-match ;; "white") ;; (set-face-inverse-video-p 'show-paren-match ;; t) ) (transient-mark-mode 1) (global-font-lock-mode 1) (setq font-lock-global-modes '(not help-mode eshell-mode ;;term-mode Man-mode)) ;; (standard-display-ascii ?\n "$\n") ;; (defvar my-eol-face ;; '(("\n" . (0 font-lock-comment-face t nil))) ;; ) ;; (defvar my-tab-face ;; '(("\t" . '(0 highlight t nil)))) (defvar my-jspace-face '(("\u3000" . '(0 highlight t nil)))) (add-hook 'font-lock-mode-hook (lambda () ;; (font-lock-add-keywords nil my-eol-face) (font-lock-add-keywords nil my-jspace-face) )) (when (safe-require-or-eval 'whitespace) (add-to-list 'whitespace-display-mappings ; not work `(tab-mark ?\t ,(vconcat "^I\t"))) (add-to-list 'whitespace-display-mappings `(newline-mark ?\n ,(vconcat "$\n"))) (setq whitespace-style '(face trailing ; trailing blanks newline ; newlines newline-mark ; use display table for newline ;; tab-mark empty ; empty lines at beg or end of buffer lines-tail ; lines over 80 )) ;; (setq whitespace-newline 'font-lock-comment-face) (global-whitespace-mode t) (if (eq (display-color-cells) 256) (set-face-foreground 'whitespace-newline "brightblack") ;; (progn ;; (set-face-bold-p 'whitespace-newline ;; t)) )) (and nil (safe-require-or-eval 'fill-column-indicator) (setq fill-column-indicator)) ;; highlight current line ;; http://wiki.riywo.com/index.php?Meadow (defface 10sr-hl-line '((((min-colors 256) (background dark)) (:background "color-234")) (((min-colors 256) (background light)) (:background "color-234")) (t (:underline "black"))) "*Face used by hl-line." :group '10sr) (global-hl-line-mode 1) ;; (hl-line-mode 1) (set-variable 'hl-line-face '10sr-hl-line) ;; (setq hl-line-face nil) (set-variable 'hl-line-global-modes '(not term-mode)) (set-face-foreground 'font-lock-regexp-grouping-backslash "#666") (set-face-foreground 'font-lock-regexp-grouping-construct "#f60") (safe-require-or-eval 'set-modeline-color) (let ((fg (face-foreground 'default)) (bg (face-background 'default))) (set-face-background 'mode-line-inactive (if (face-inverse-video-p 'mode-line) fg bg)) (set-face-foreground 'mode-line-inactive (if (face-inverse-video-p 'mode-line) bg fg))) (set-face-underline 'mode-line-inactive t) (set-face-underline 'vertical-border nil) ;; Not found in MELPA nor any other package repositories (and (fetch-library "https://raw.github.com/tarao/elisp/master/end-mark.el" t) (safe-require-or-eval 'end-mark) (global-end-mark-mode)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; file handling (when (safe-require-or-eval 'editorconfig) (editorconfig-mode 1)) (setq revert-without-query '(".+")) ;; save cursor position (when (safe-require-or-eval 'saveplace) (setq-default save-place t) (setq save-place-file (concat user-emacs-directory "places"))) ;; http://www.bookshelf.jp/soft/meadow_24.html#SEC260 (setq make-backup-files t) ;; (make-directory (expand-file-name "~/.emacsbackup")) (setq backup-directory-alist (cons (cons "\\.*$" (expand-file-name (concat user-emacs-directory "backup"))) backup-directory-alist)) (setq version-control 'never) (setq delete-old-versions t) (setq auto-save-list-file-prefix (expand-file-name (concat user-emacs-directory "auto-save/"))) (setq delete-auto-save-files t) (add-to-list 'completion-ignored-extensions ".bak") ;; (setq delete-by-moving-to-trash t ;; trash-directory "~/.emacs.d/trash") (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) (set (defvar bookmark-default-file) (expand-file-name (concat user-emacs-directory "bmk"))) (add-hook 'recentf-load-hook (lambda () (defvar recentf-exclude) (add-to-list 'recentf-exclude (regexp-quote bookmark-default-file)))) (when (safe-require-or-eval 'smart-revert) (smart-revert-on)) ;; autosave (when (safe-require-or-eval 'autosave) (autosave-set 2)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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 "