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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章