AICurious Logo
Published on
Friday, August 25, 2017

Xây dựng một cấu hình Emacs từ đầu

3096 words16 min read
Authors

Emacs là một trình soạn thảo văn bản đa chức năng và có thể mở rộng các chức năng một cách mạnh mẽ. Khi chưa cấu hình (tất cả thiết lập để ở mặc định), Emacs có thể coi là trình soạn thảo hơi khó dùng, giao diện khá đơn giản, nếu không nói là xấu. Tuy nhiên khi tuỳ biến bằng các tệp cấu hình, bạn có thể biến Emacs thành bất cứ thứ gì bạn muốn. Đó là lý do Emacs có thể tồn tại được từ lần đầu tiên nó được sinh ra (năm 1976) cho tới nay và luôn là một trong các trình soạn thảo code được nhiều lập trình viên sử dụng nhất. Trong bài viết này tôi sẽ hướng dẫn các bạn cấu hình cơ bản Emacs từ đầu cho tới khi trở thành một trình soạn thảo đem lại cho bạn cảm giác thoải mái.

Một số hình ảnh về Emacs sử dụng các cấu hình khác nhau:

Emacs mặc định

GNU Emacs cấu hình mặc định - Hình ảnh từ trang chủ.

Spacemacs

Spacemacs - Một cấu hình Emacs được phát triển bởi cộng đồng

Emacs

Bản Emacs với cấu hình tôi đang dùng để viết bài viết này và sẽ hướng dẫn các bạn tạo một cái tương tự.

Tệp cấu hình Emacs ở đâu?

Bạn có thể chỉnh sửa cấu hình Emacs tại file ~/.emacs.el hoặc ~/.emacs.d/init.el.

Trong khuôn khổ bài viết này, tôi chỉ hướng dẫn các bạn cấu hình từ đầu bằng cách dùng file ~/.emacs.d/init.el. Bạn có thể sử dụng bất kì editor nào bạn muốn để thực hiện việc chỉnh sửa file này (có thể là chính Emacs, tuy nhiên bạn sẽ phải mở lại file cấu hình liên tục mỗi khi khởi động lại Emacs để xem kết quả nếu bạn dùng nó).

Tạo file cấu hình từ đầu

Hãy tạo 1 file cấu hình để chúng ta bắt đầu làm việc từ đầu bằng cách xoá file ~/.emacs.el và tất cả các file trong thư mục ~/.emacs.d, sau đó tạo file mới ~/.emacs.d/init.el.

Sau khi có một file cấu hình mới tên init.el, bạn hãy thực hiện tiếp các bước bên dưới để thêm nội dung vào.

Nạp package manager

Package manager (giống Package control bên Sublime Text) giúp bạn quản lí, cài đặt các gói tính năng bổ sung cho trình soạn thảo.

Thêm đoạn code sau để load package manager lên và thêm kho plugin "melpa":

;; Load package manager
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)

Trong bài viết này tôi sẽ sử dụng thêm một gói tên use-package để tự động quản lí việc tải về các package khác và tăng đáng kể tốc độ khởi động Emacs.

Đặt đoạn code sau ngay phía dưới đoạn trên:

;; Load `use-package`
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))
(eval-when-compile
  (require 'use-package))
(require 'diminish)
(require 'bind-key)

(setq use-package-always-ensure t)

Tuỳ biến các giao diện chính

Đổi theme

Trong cấu hình này tôi sẽ sử dụng theme monokai (theme màu tối được khá nhiều người ưa thích). Bạn cũng có thể tìm các theme khác từ Google nhé.

;; Load editor theme
(use-package monokai-theme
  :config (load-theme 'monokai t))

Ẩn các thanh công cụ, menu, thanh cuộn mặc định

Đôi khi việc có thêm các thanh menu, thanh cuộn chỉ làm bạn mất tập trung. Hãy loại bỏ chúng bằng cách thêm đoạn code sau (Lưu ý nếu bạn muốn giữ lại thứ gì hãy comment lại dòng tương ứng bằng cách để dấu ; ở đầu dòng).

;; Turn off menubar, toolbar, scollbar
(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
Emacs Toolbar Menubar Scrollbar

Hiện line number (số dòng khi soạn code)

;; Display line number when programming
(add-hook 'prog-mode-hook 'linum-mode)
(setq linum-format "%4d \u2502")

Cài đặt tab-indent

(setq tab-width 4)

Word wrap

Mặc định Emacs sẽ cắt dòng bằng cách cắt đôi một từ. Dòng sau sẽ giúp cài đặt Emacs chỉ xuống dòng khi viết hết từ.

(global-visual-line-mode t)

Tô sáng các ngoặc tương ứng nhau

Sử dụng code sau giúp tô sáng ngoặc tương ứng khi bạn để con trỏ lên một ngoặc.

;; Display paren (highlight matching brackets)
(show-paren-mode 1)
(setq show-paren-delay 0)

Đổi Font chữ

Tôi rất thích sử dụng font "Source Code Pro" của Adobe khi code. Do vậy tôi sẽ đổi font mặc định của Emacs:

  • Cài Font "Source Code Pro" của Adobe bằng cách tải về từ github https://github.com/adobe-fonts/source-code-pro và thực hiện cài đặt theo hệ điều hành sử dụng.

  • Sau khi cài font "Source Code Pro", thêm đoạn sau vào file cấu hình Emacs:

(set-face-attribute 'default nil
                    :family "Source Code Pro"
                    :height 160
                    :weight 'normal
                    :width 'normal)

Cá nhân hoá "Lời chào" khi khởi động Emacs

Có một cấu hình khác hay trong Emacs giúp bạn tạo ra một màn hình "Lời chào" mỗi khi bật Emacs thay vì màn hình trợ giúp mặc định của nó. Thêm code sau vào file cấu hình (sửa lời chào của tôi thành cái của bạn nhé - có thể dùng markdown để lời chào thêm sinh động).

;; Display startup message
(setq initial-scratch-message "

# EMACS CONFIGURATION BY VIET-ANH NGUYEN
# VERSION : 1.0

## Email: ...
## Website: ...

## Welcome! Hope my configuration can help you.

")

(setq inhibit-startup-message t)
(setq initial-major-mode 'markdown-mode)

Một số tuỳ biến giao diện nâng cao

Cuộn trang mượt hơn, chế độ xem thẩm mĩ và minimap giống Sublime Text

Nếu bạn lựa chọn trình soạn thảo Sublime Text vì những thứ trên và ghét Emacs ở chỗ mỗi khi bạn cuộn trang (C-v, M-v) thì Emacs sẽ ngay lập tức chuyển sang vị trí tiếp theo, không có hiệu ứng cuộn, hay bạn thích 1 trình soạn thảo có thêm chức năng minimap("bản đồ" thu nhỏ của code), xem văn bản kiểu attractive (căn lề 2 bên để tăng tính thẩm mĩ), xin trả lời Emacs cũng làm được như vậy với package sublimity. Chỉ cần thêm đoạn code sau:

;; Smooth Scrolling and attractive mode (look like Sublime Text)
(use-package sublimity
  :config
  (require 'sublimity-scroll)
  ;; (require 'sublimity-map) ;; experimental
  (require 'sublimity-attractive)
  (sublimity-mode 1)
  )

Cá nhân tôi không thích chế độ xem minimap nên tôi sẽ comment dòng ;; (require 'sublimity-map) ;; experimental. Chỉ cần bỏ ;; đầu dòng đó là chức năng trên sẽ được kích hoạt.

Screenshot (Nguồn sublimity):

Sublimity - Emacs

Thêm chức năng Directory view (Hiện cây thư mục các file trong dự án ở bên trái)

Ở đây mình sẽ sử dụng đến package tên "neotree" cho chức năng hiện cây thư mục và "all-the-icons" cho hiển thị các icon đẹp cho thư mục và tệp.

Cài all-the-icons

Thêm dòng:

(use-package all-the-icons)

Tiếp theo, khởi động lại Emacs và gõ M-x all-the-icons-install-fonts để cài các icon font vào hệ thống.

Cài neotree

;; Display a directory tree view on the left side
(use-package neotree
 :config (progn
	  (setq neo-theme (if (display-graphic-p) 'icons 'arrow)))
 :bind ("C-x n o" . neotree-toggle))

Sau khi khởi động lại một lần nữa và chờ tới khi neotree được cài đặt, bạn có thể gõ C-x n o để bật/tắt chế độ xem cây thư mục.

Screenshot

Hình ảnh neotree Emacs

Thêm NyanCat (hình con mèo bay) ở dưới thanh Modeline để biểu thị vị trí chuột so với văn bản

;; NyanCat on Modeline as an analog indicator of your position in the buffer
(use-package nyan-mode
  :config
  (nyan-mode)
  )

Bạn có thể ghé qua https://github.com/TeMPOraL/nyan-mode để tìm hiểu thêm một số thiết lập animation (hoạt hình) cho NyanCat.

Hình ảnh thanh NyanCat:

Nyancat

Tăng cường chức năng tìm kiếm và tự động hoàn thành

Thay thế chức năng tìm kiếm, tự hoàn thành mặc định bằng Ivy

Các chức năng tìm kiếm, tự hoàn thành mặc định có thể thay thế bằng một framework tuyệt vời tên Ivy. Bạn cũng có thể dùng Helm - framework khá mạnh mẽ được nhiều người dùng. Tuy nhiên vì Helm có quá nhiều chức năng, nó sẽ khiến Emacs chậm đi đáng kể tôi quyết định chọn Ivy.

Thêm đoạn code sau vào file cấu hình và khởi động lại. Thử một chức năng như tìm kiếm C-s hay M-x để xem sự khác biệt so với các mặc định của Emacs.

;; Replace default completion frontend with Ivy
;; https://github.com/abo-abo/swiper
(use-package counsel
  :config (ivy-mode 1)
  :init
  (progn
    (setq ivy-use-virtual-buffers t)
    (setq enable-recursive-minibuffers t)
    (global-set-key "\C-s" 'swiper)
    (global-set-key (kbd "C-c C-r") 'ivy-resume)
    (global-set-key (kbd "<f6>") 'ivy-resume)
    (global-set-key (kbd "M-x") 'counsel-M-x)
    (global-set-key (kbd "C-x C-f") 'counsel-find-file)
    (global-set-key (kbd "<f1> f") 'counsel-describe-function)
    (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
    (global-set-key (kbd "<f1> l") 'counsel-find-library)
    (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
    (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
    (global-set-key (kbd "C-c g") 'counsel-git)
    (global-set-key (kbd "C-c j") 'counsel-git-grep)
    (global-set-key (kbd "C-c k") 'counsel-ag)
    (global-set-key (kbd "C-x l") 'counsel-locate)
    (global-set-key (kbd "C-S-o") 'counsel-rhythmbox)
    (define-key read-expression-map (kbd "C-r") 'counsel-expression-history))
  )

Tự hoàn thành code và chức năng Snippet

Autocomplete : company

;; Autocomplete
(use-package company
  :config (global-company-mode t))

Thêm các snippets từ gói yasnippet cho nhiều ngôn ngữ

;; Snippets
(use-package yasnippet
  :defer t
  :init
  (yas-global-mode 1))

Tự động check lỗi lập trình theo thời gian thực

Ở đây tôi dùng Flycheck thay cho Flymake mặc định trên Emacs.

;;;; FLYCHECK  - REALTIME ERROR CHECKING ===============
(use-package flycheck
  :config
  (global-flycheck-mode)
  (setq flycheck-check-syntax-automatically '(mode-enabled save))
  )

Thêm một số phím tắt chức năng cho Emacs

Comment/Uncomment các dòng code

Thêm đoạn code sau và bạn có chức năng comment tương tự các editor khác như Sublime Text (sử dụng C-c c để toggle comment cho các dòng code được bôi đen).

(defun xah-comment-dwim ()
  "Like `comment-dwim', but toggle comment if cursor is not at end of line."
  (interactive)
  (if (region-active-p)
      (comment-dwim nil)
    (let ((-lbp (line-beginning-position))
          (-lep (line-end-position)))
      (if (eq -lbp -lep)
          (progn
            (comment-dwim nil))
        (if (eq (point) -lep)
            (progn
              (comment-dwim nil))
          (progn
            (comment-or-uncomment-region -lbp -lep)
            (forward-line )))))))
(global-set-key (kbd "C-c c") 'xah-comment-dwim)

Quản lí các buffer

;; Manage buffers
(defun switch-to-previous-buffer ()
  "Switch to previously open buffer.
Repeated invocations toggle between the two most recently open buffers."
  (interactive)
  (switch-to-buffer (other-buffer (current-buffer) 1)))
(use-package key-chord
  :config
  (progn
  (key-chord-mode 1)
  (key-chord-define-global "jj" 'switch-to-previous-buffer)
  (key-chord-define-global "kk" 'next-buffer))
  (key-chord-define-global "gg" 'goto-line)
  (key-chord-define-global "yy" 'other-window)
  (key-chord-define-global "xx" 'kill-buffer))

Ở đây tôi dùng các keychord để quản lí các buffer. Keychord được kích hoạt bằng cách ấn liên tục chuỗi phím trên bàn phím. Ví dụ bạn có thể ấn liên tiếp jj để chuyển qua buffer trước đó. Các keychord dùng quản lí buffer và chức năng của chúng được mô tả trong bảng dưới đây.

Keychord Function
jj Chuyển qua buffer trước đó
kk Chuyển qua buffer sau
gg Đi tới một dòng (Nhập vào số dòng)
yy Nhảy giữa các buffer trên màn hình
xx Đóng buffer (kill)

Di chuyển giữa các cửa sổ (buffer đang hiện trên màn hình)

Việc này sẽ được thực hiện bằng cách ấn C-c và theo sau là một phím mũi tên.

;; Move between windows
(global-set-key (kbd "C-c <left>")  'windmove-left)
(global-set-key (kbd "C-c <right>") 'windmove-right)
(global-set-key (kbd "C-c <up>")    'windmove-up)
(global-set-key (kbd "C-c <down>")  'windmove-down)

Thay đổi thích thước các cửa sổ

Việc này được thực hiện bằng cách ấn C-s (phím Ctrl và phím cửa sổ, command) cùng lúc với một phím mũi tên.

;; Resize windows
(global-set-key (kbd "C-s-<left>") 'shrink-window-horizontally)
(global-set-key (kbd "C-s-<right>") 'enlarge-window-horizontally)
(global-set-key (kbd "C-s-<down>") 'shrink-window)
(global-set-key (kbd "C-s-<up>") 'enlarge-window)

Multiple cursors (đa con trỏ)

Đây là một trong những chức năng khá hay trong các editor hiện đại giúp lập trình viên chỉnh sửa cùng lúc nhiều dòng code. Việc này được cài đặt trên Emacs bằng cách sử dụng package multiple-cursors.

;;;; MULTIPLE CURSORS ==================================
(use-package multiple-cursors
  :bind (("C-x c" . mc/edit-lines)
         ("C->" . mc/mark-next-like-this)
         ("C-<" . mc/mark-previous-like-this)
         ("C-c C-<" . mc/mark-all-like-this)
	 ("C-S-<down-mouse-1>" . mc/add-cursor-on-click)
       )
)
;;;; ===================================================

Xem thêm về cách sử dụng và các cấu hình khác tại multiple-cursors.

Một demo về sử dụng package này trên Emacs Rocks:

http://emacsrocks.com/e13.html