Emacs神器初养成

文本编辑器是程序员日常工作生活中不可缺少的重要工具。优秀的文本编辑器可以解放劳动力、提高生产率。在程序员的世界里效率是一件重要的事情。因此,文本编辑器之争也就成为大家茶余饭后的谈资(如同程序设计语言一样)。我向来是一个自由主义者。谁好谁坏这种事情,所持的观点和角度不同,有时候很难分辨。程序员和文本编辑器之间的关系,应该有点像谈恋爱,萝卜青菜各有所爱。

 

Emacs是编辑器排行榜中争论较为突出的一位,支持者声称Emacs是世界上最好用的编辑器(因为配置和扩展的能力实在太强,它确实不仅仅是个文本编辑器,还是IDE、日历/日程/约会管理器、邮件客户端、Web浏览器、命令终端、图片浏览、音乐播放、视频编辑等,甚至曾有人把它比成操作系统.....)。反对者也能列举它诸多不是,将其与神经病、抓狂相联系(比如太多的快捷键绑定把手指头都搞抽筋,比如太古老,比如配置起来太复杂,比如启动的速度可以赶超操作系统等等)。其实采纳两方观点,才能把Emacs看得更清楚。扯远了,回到正题。

 

话说我和Emacs之间的过往,不严格的说从大学时代就已经开始。那个时候仅仅以为它是古董又蹩脚的东西,21世纪的新新软件工程师还有谁会使用它。所以是只闻其名,未见其身。大学毕业工作三年后,一个偶然的机会,我踏进了Emacs的世界(一是因为踏进了lisp世界,二是出于对古董级物品难以遏制的好奇心。)。了解了lisp之后,发现原来Emacs的配置和开发并不是很恐怖,也体会到这个所谓的无所不能的神器的震撼,“Emacs只不过是伪装成编辑器的操作系统这句话真的一点也不假。

 

古董级的东西还能活在现今的世界中,一定有它的原因。“Emacs is a refugee from the long dead culture of Lisp Machines

 

以上扯的更远了,再回到正题。


既然本篇的题为神器的养成,那么还是要谈谈我在使用Emacs后的一些心得(这才是正题)。对于像我这样用惯了新一代编辑器(主要在微软平台上)新新软件工程师,脑海中形成了固化的概念,傻子式、所见即所得、图形界面形式的编辑器很好用很给力。这个概念说的通用些因为学习曲线短所以认为很好用很给力。但如果把这样的概念应用到Emacs上,不合适!Emacs是疯子式(天才式)、所按即所得、提供复杂编辑功能的编辑器。Emacs的概念说的通用些它不想你一来就上手。学习曲线必须是相当的陡峭。开始使用的时候一点力也不给你。但它关心的是你学成之后,无所不能。

 

如果把学习和使用编辑器比作登山。那普通的编辑器不过是个丘陵,你登的容易登不高。Emacs是珠穆朗玛峰,一般人不轻易去登它,二般人只有两个结果,要么登顶要么牺牲。

 

想要登珠峰,除了练就一身好体魄,还有有坚持不懈地决心。所以这应该是Emacs使用者应该持有的态度吧。

 

光有态度恐怕还不行,还需要方法。那么什么方法呢,其实很简单。只要记住几个非常重要快捷键,一个非常重要的文件,还有若干网站,这就是登山装备了。说的确切点,

                 快捷键是Ctrl-h t, Ctrl-h i, Ctrl-h f, Ctrl-h v, Ctrl-h d, Ctrl-h b, Ctrl-h nCtrl-h作为前缀的帮助快捷键。

                 文件是大名鼎鼎的dot emacs文件(.emacs配置文件)

                 网站是http://www.emacswiki.org/http://emacser.com/about.htm或者直接google好了。

 

 

 

 

最后的最后,贴出我初养成的神器Emacsdot emacs。以待后日成为大牛时作个参考。

 


 

(require 'ido)

;;使用CVS版本,因为Emacs 23中已经有内欠的CEDET了,所以必须明确load-file
(load-file "~/.emacs.d/contrib/cedet/common/cedet.el")
(require 'eassist)
 
;;所有扩展包都在.emacs.d的contrib目录下
(let ((default-directory "~/.emacs.d/"))
  (normal-top-level-add-subdirs-to-load-path))
(require 'color-theme)
(require 'maxframe)
(require 'traverselisp)
(require 'session)
 
(require 'auto-complete-config)
(require 'yasnippet)
(require 'ecb-autoloads)
 
(require 'org)
(require 'muse-mode)
(require 'muse-publish)
(require 'muse-html)
(require 'emacs-wiki)
 
(require 'slime)
(require 'cc-mode)
 
;; 还有一些扩展包包含在emacs-goodies-el中,用的是debian系统
(add-to-list 'load-path "/usr/share/emacs/site-lisp/emacs-goodies-el/" t)
(require 'tabbar)
(require 'highlight-current-line)
(require 'pack-windows)
;;;;;;;;;;;;;;;很多适合我的配置;;;;;;;;;;;;;;;;;;;;  
;;Custom Setting 
(custom-set-variables
  ;; custom-set-variables was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(auto-image-file-mode t)
 '(calendar-mark-diary-entries-flag t)
 '(calendar-mark-holidays-flag t)
 '(calendar-week-start-day 1)
 '(column-number-mode t)
 '(desktop-base-file-name ".emacs.d/.desktop")
 '(desktop-base-lock-name ".emacs.d/.desktop.lock")
 '(desktop-save-mode t)
 '(display-time-24hr-format t)
 '(display-time-day-and-date t)
 '(display-time-format "%A %B %d %T %Z")
 '(display-time-interval 1)
 '(display-time-mail-function nil)
 '(display-time-mode t)
 '(display-time-world-list (quote (("PST8PDT" "Seattle") ("EST5EDT" "New York") ("GMT0BST" "London") ("CET-1CDT" "Paris") ("IST-5:30" "Bangalore") ("JST-9" "Tokyo") ("CST-8" "BeiJing"))))
 '(display-time-world-time-format "%A %B %d %T %Z")
 '(display-time-world-timer-second 1)
 '(ecb-options-version "2.40")
 '(ede-project-placeholder-cache-file "~/.emacs.d/.projects.ede")
 '(gdb-many-windows nil)
 '(highlight-current-line-globally t nil (highlight-current-line))
 '(highlight-current-line-whole-line t)
 '(holiday-hebrew-holidays nil)
 '(holiday-islamic-holidays nil)
 '(holiday-solar-holidays nil)
 '(ido-create-new-buffer (quote always))
 '(ido-enable-last-directory-history nil)
 '(ido-max-work-directory-list 0)
 '(ido-max-work-file-list 0)
 '(ido-mode (quote buffer) nil (ido))
 '(ido-record-commands nil)
 '(image-load-path (quote ("~/.emacs.d/" "/usr/local/share/emacs/23.2/etc/images/" data-directory load-path "")))
 '(inhibit-startup-buffer-menu t)
 '(inhibit-startup-echo-area-message "nixie")
 '(inhibit-startup-screen t)
 '(initial-buffer-choice nil)
 '(initial-scratch-message nil)
 '(kill-do-not-save-duplicates t)
 '(kill-ring-max 500)
 '(legacy-style-world-list (quote (("PST8PDT" "Seattle") ("EST5EDT" "New York") ("GMT0BST" "London") ("CET-1CDT" "Paris") ("IST-5:30" "Bangalore") ("JST-9" "Tokyo") ("CST-8" "BeiJing"))))
 '(make-backup-files nil)
 '(max-lisp-eval-depth 1048576)
 '(max-specpdl-size 1048576)
 '(save-interprogram-paste-before-kill t)
 '(scroll-conservatively 100000)
 '(scroll-margin 3)
 '(scroll-step 1)
 '(semantic-c-dependency-system-include-path (quote ("/usr/include" "/usr/local/include/opencv")))
 '(semantic-idle-scheduler-idle-time 0.5)
 '(show-paren-mode t)
 '(tabbar-background-color "yellow")
 '(tabbar-mode t nil (tabbar))
 '(uniquify-buffer-name-style (quote forward) nil (uniquify))
 '(x-select-enable-clipboard t)
 '(yank-pop-change-selection t)
 '(yas/trigger-key (kbd "C-x C-y"))
 '(zoneinfo-style-world-list (quote (("America/Los_Angeles" "Seattle") ("America/New_York" "New York") ("Europe/London" "London") ("Europe/Paris" "Paris") ("Asia/Calcutta" "Bangalore") ("Asia/Tokyo" "Tokyo") ("Asia/BeiJing" "BeiJing")))))
(custom-set-faces
  ;; custom-set-faces was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(highlight-current-line-face ((t (:background "yellow" :foreground "black" :inverse-video t :weight bold))))
 '(tabbar-default ((((class color grayscale) (background dark)) (:inherit variable-pitch :background "gray50" :foreground "grey75")))))
 
(put 'upcase-region 'disabled nil)
;;;;;;;;;;;;;;;;;;;扩展功能的一些初始化;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
;; Color-Theme 
(eval-after-load "color-theme" 
  '(progn (color-theme-initialize)
	  (color-theme-calm-forest)))
 
;;Auto-complete
(add-to-list 'ac-dictionary-directories "~/.emacs.d/contrib/auto-complete/dict/")
(ac-config-default)
 
;;Yasnippet
(yas/initialize)
(yas/load-directory "~/.emacs.d/contrib/yasnippet/snippets")
 
;; Exempted from auto-complete-yasnippet.el
(defun ac-yasnippet-candidate-1 (table)
  (let ((hashtab (yas/snippet-table-hash table))
        (parent (yas/snippet-table-parent table))
        candidates)
    (maphash (lambda (key value)
               (push key candidates))
             hashtab)
    (setq candidates (all-completions ac-prefix (nreverse candidates)))
    (if parent
        (setq candidates
              (append candidates (ac-yasnippet-candidate-1 parent))))
    candidates))
 
(defun ac-yasnippet-candidate ()
  (let ((table (yas/snippet-table major-mode)))
    (if table
        (ac-yasnippet-candidate-1 table))))
 
(defface ac-yasnippet-candidate-face 
  '((t (:background "sandybrown" :foreground "black")))
  "Face for yasnippet candidate.")
 
(defface ac-yasnippet-selection-face 
  '((t (:background "coral3" :foreground "white")))
  "Face for the yasnippet selected candidate.")
 
(defvar ac-source-yasnippet 
  '((candidates . ac-yasnippet-candidate)
    (action . yas/expand)
    (limit . 3)
    (candidate-face . ac-yasnippet-candidate-face)
    (selection-face . ac-yasnippet-selection-face))
  "Source for Yasnippet.")
 
;; CEDET
(global-ede-mode 1)
(semantic-load-enable-minimum-features)
(semantic-load-enable-code-helpers)
;;(semantic-load-enable-guady-code-helpers) 
;;(semantic-load-enable-excessive-code-helpers) 
(semantic-load-enable-semantic-debugging-helpers)
(global-semantic-highlight-func-mode 1)
(if (fboundp #'which-func-mode)
    (add-hook 'semantic-init-hook (lambda ()
				    (which-func-mode 1))))
(global-srecode-minor-mode 1)
 

(when (and (require 'semantic-tag-folding nil 'noerror))
  (global-semantic-tag-folding-mode 1)
  (global-set-key (kbd "C-?") 'global-semantic-tag-folding-mode)
  (define-key semantic-tag-folding-mode-map (kbd "C-c -") 'semantic-tag-folding-fold-block)
  (define-key semantic-tag-folding-mode-map (kbd "C-c =") 'semantic-tag-folding-show-block)
  (define-key semantic-tag-folding-mode-map (kbd "C-c M--") 'semantic-tag-folding-fold-all)
  (define-key semantic-tag-folding-mode-map (kbd "C-c M-=") 'semantic-tag-folding-show-all))
 
(enable-visual-studio-bookmarks)
 
;; Slime
(setq slime-lisp-implementations
      `((sbcl ("~/.emacs.d/contrib/sbcl/src/runtime/sbcl" 
	       "--core" 
	       ,(file-truename "~/.emacs.d/contrib/sbcl/output/sbcl.core"))
	      :env ,(list (format "SBCL_HOME=%s" (file-truename "~/.emacs.d/contrib/sbcl/contrib/"))))))
(slime-setup '(slime-fancy slime-repl slime-scratch slime-editing-commands))
 
;;;;;;;;;;;;;;;;;;适合我的设置;;;;;;;;;;;;;;;;;;;;;;;;;;; 
(global-set-key (kbd "C-x 9") 'maximize-frame);;这个没有ubuntu下面系统默认的alt+f10好用
 
;; Enable IDO Mode
(ido-mode 1)

;;管理诸多Buffer实在很烦,索性用一个键删除之。开始不习惯,删除一个字母的时候老按delete,结果......
(global-set-key (kbd "<delete>") 'kill-buffer-and-window)
;;把所有不想要的Buffer都一个键删了去。
(defun kill-other-buffers (&rest buffers-not-to-kill)
  "Kill buffers not listed in arguements. 
If the arguements are nil, all buffers except current buffer will be killed" 
  (interactive)
  (let ((buffers-all (buffer-list))
	(buffers-not-to-kill (or buffers-not-to-kill
				 (list (current-buffer))))
	(kill-buffer-query-functions nil))
    (mapc 'kill-buffer
	  (remove-if (lambda (buffer)
		       (memq buffer buffers-not-to-kill))
		     buffers-all))))
 
(global-set-key (kbd "S-<delete>")
		(lambda ()
		  (interactive)
		  (kill-other-buffers (current-buffer) 
				      (get-buffer "*scratch*") 
				      (get-buffer "*Messages*"))
		  (call-interactively 'delete-other-window)))
 
 
;; 列出buffer的时候,最好跳到list中,让我选择。
(global-set-key (kbd "C-x C-b") (lambda ()
				  (interactive)
				  (call-interactively 'list-buffers)
				  (call-interactively 'other-window)))				  
 
;;Save Session when exit
(add-hook 'after-init-hook 'session-initialize)
 
;; Toggle Visual Line Mode
(global-set-key (kbd "C-x M-T") (lambda nil (interactive)
				   (if visual-line-mode 
				       (visual-line-mode 0))
				   (setq word-wrap nil) 
				   (if truncate-lines
				       (toggle-truncate-lines -1)
				     (toggle-truncate-lines 1))))
 
(global-set-key (kbd "C-`") (lambda ()
			      (interactive)
			      (if (or (not (fboundp 'calendar-exit)) 
				      (null (calendar-exit)))
				  (calendar))))
 
;; 从emacen.com那里抄来,忒好用了
(defun isearch-current-word-forward (&optional regexp-p no-recursive-edit)
  (interactive "P/np")
  (isearch-mode t (not (null regexp-p)) nil (not no-recursive-edit))
  (isearch-yank-string (current-word)))
 
(defun isearch-current-word-backward (&optional regexp-p no-recursive-edit)
  (interactive "P/np")
  (isearch-mode nil (not (null regexp-p)) nil (not no-recursive-edit))
  (isearch-yank-string (current-word)))
 
(global-set-key (kbd "C-*") 'isearch-current-word-forward)
(global-set-key (kbd "C-#") 'isearch-current-word-backward)
 
(define-key isearch-mode-map (kbd "C-*") 'isearch-repeat-forward)
(define-key isearch-mode-map (kbd "C-#") 'isearch-repeat-backward)
;;;;;;;;;;;;;;;我实在习惯了Visual Studio了,一时还改不过来;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
;;C/C++ FN keys 
(defun define-c-mode-fn-key-debug ()
  (define-key c-mode-base-map (kbd "<f5>") 'gud-go)
  (define-key c-mode-base-map (kbd "<f10>") 'gud-step)
  (define-key c-mode-base-map (kbd "<f11>") 'gud-next)
  (define-key c-mode-base-map (kbd "S-<f10>") 'gud-finish)
  (define-key c-mode-base-map (kbd "<f9>") 'gud-break)
  (define-key c-mode-base-map (kbd "S-<f9>") 'gud-remove)
 
  (define-key gud-mode-map (kbd "<f5>") 'gud-go)
  (define-key gud-mode-map (kbd "<f10>") 'gud-step)
  (define-key gud-mode-map (kbd "<f11>") 'gud-next)
  (define-key gud-mode-map (kbd "S-<f10>") 'gud-finish)
  (define-key gud-mode-map (kbd "<f9>") 'gud-break))
 
(defun define-c-mode-fn-key-edit ()
  ;;Code Reference
  (define-key c-mode-base-map (kbd "<f12>") (lambda ()
					      (interactive)
					      (if (semantic-tag-of-class-p (semantic-current-tag) 'include)
						  (progn 
						    (push-mark)
						    (when (fboundp 'push-tag-mark)
						      (push-tag-mark))))
					      (semantic-ia-fast-jump (point))))
  (define-key c-mode-base-map (kbd "S-<f12>") (lambda ()
						(interactive)
						(if (ring-empty-p (oref semantic-mru-bookmark-ring ring))
						    (error "Semantic Bookmark Ring is empty"))
						(let* ((ring (oref semantic-mru-bookmark-ring ring))
						       (alist (semantic-mrub-ring-to-assoc-list ring))
						       (first (cdr (car alist))))
						  (if (semantic-equivalent-tag-p (oref first tag)
										 (semantic-current-tag))
						      (setq first (cdr (car (cdr alist)))))
						  (semantic-mrub-switch-tags first))))
  (define-key c-mode-base-map (kbd "M-<f12>") 'eassist-switch-h-cpp)
  (define-key c-mode-base-map (kbd "M-S-<f12>") 'semantic-analyze-proto-impl-toggle)
 
  (define-key c-mode-base-map (kbd "<f8>") (lambda ()
					     (interactive)
					     (call-interactively 'ecb-minor-mode)))
 
  ;;Compile and Debug
  (define-key c-mode-base-map (kbd "<f6>") (lambda ()
					     (interactive)
					     (compile "make -k")))
  (define-key c-mode-base-map (kbd "<f5>") (lambda ()
					     (interactive)				     
					     (call-interactively 'gdb)))
  (define-key c-mode-base-map (kbd "S-<f5>") (lambda ()
					       (interactive)				     
					       (call-interactively 'gdb)
					       (call-interactively 'gdb-many-windows)))
  (define-key c-mode-base-map (kbd "M-<f5>") (lambda ()
					       (interactive)
					       (compile "make -k")
					       (call-interactively 'gdb)))
  (define-key c-mode-base-map (kbd "M-S-<f5>") (lambda ()
						 (interactive)
						 (compile "make -k")				     
						 (call-interactively 'gdb)
						 (call-interactively 'gdb-many-windows))))
 
;; Close compilation buffer if successful
(add-to-list 'compilation-finish-functions
	     (lambda (buffer string)
	       (when (and (string= (buffer-name buffer) "*compilation*")
			  (not (string-match "exited abnormally" string)))
		 (run-at-time 2.5 nil 'delete-windows-on buffer))))
 
;; 当gdb/gud结束的时候,最好回到代码窗口,或者回到*scratch*好了
(defun kill-buffers-when-gdb-quit ()
  "Close gdb buffer when gdb quit. This function is invoked when gdb mode is enabled with gdb-mode-hook" 
  (let ((process (get-buffer-process (current-buffer))))
    (when (processp process)
      (set-process-sentinel process 
			    (lambda (proc change)
			      (when (string-match "//(finished//|exited//|killed//)" change)
				(condition-case nil
				    (progn 
				      (gdb-many-windows -1)
				      (delete-other-windows 
				       (get-buffer-window
					(switch-to-buffer 
					 (condition-case nil
					     (gud-find-file gdb-main-file)
					   (error "*Scratch*")))))
				      (define-c-mode-fn-key-edit)
				      (gud-reset)
				      (gdb-reset)					  
				      (kill-buffer (process-buffer proc)))
				  (error nil))))))))
;; (defun gud-kill () 
;;   "kill gdb process"
;;   (interactive)
;;   (with-current-buffer gud-comint-buffer (comint-skip-input))
;;   (set-process-query-on-exit-flag (get-buffer-process gud-comint-buffer) nil)
;;   (kill-buffer gud-comint-buffer))
 
(mapc (lambda (mode-hook)
	(add-hook mode-hook (lambda ()
			      (kill-buffers-when-gdb-quit)
			      (define-c-mode-fn-key-debug))))
      (list 'gdb-mode-hook 'gud-mode-hook))
 
(mapc (lambda (mode-hook)
	(add-hook mode-hook (lambda ()
			      (progn 
				(linum-mode 1)
				(define-c-mode-fn-key-edit)
				(tool-bar-add-item "gud" 'gdb 'gdb :visible '(memq major-mode '(c++-mode c-mode)))
				(tool-bar-add-item "compile" 'compile 'compile :visible '(memq major-mode '(c++-mode c-mode)))))))
      (list 'c-mode-hook 'c++-mode-hook))
 
;; C/C++ Comment Kill
(fset 'kill-c-comment
      (lambda (&optional arg) 
	"Keyboard macro." 
	(interactive "p") 
	(kmacro-exec-ring-item 
	 (quote ("/223////|///*/273" 0 "%d")) 
	 arg)))
(define-key c-mode-base-map (kbd "C-x M-K") 'kill-c-comment)
 
(fset 'kill-c-blank-line
      (lambda (&optional arg) 
	"Keyboard macro." 
	(interactive "p") 
	(kmacro-exec-ring-item 
	 (quote ("/223^[[:space:]]*$" 0 "%d")) 
	 arg)))
(define-key c-mode-base-map (kbd "C-x C-K") 'kill-c-blank-line)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章