Install Emacs on Windows 10

By | 2022년 3월 19일
Table of Contents

Install Emacs on Windows 10

Emacs 설치

https://www.gnu.org/software/emacs/ 에서 이맥스를 다운받아 설치합니다.

환경 변수 설정

HOME 환경변수를 추가합니다.

Emacs 실행

우선 Emacs 를 실행시켜 봅니다.
(설치된 폴더 안에 bin 디렉토리가 있는데 그 안으로 들어가면 emacs.exe 가 있습니다.)

가장 중요한 Ctrl-C/Ctrl-V 가 오작동하는것을 교정하기 위해 아래 설정을 합니다.
메뉴 > Options > Use CUA Keys 체크.

폰트가 맘에 않들면 아래와 같이 합니다.
메뉴 > Options > Set Default Font 를 선택하면 폰트를 고를 수 있습니다.

툴바가 않이쁘면 아래와 같이 합니다.
메뉴 > Options > Show/Hide > Tool-bar

옵션정보를 저장하지 않으면 이맥스를 재실행 했을 때 다시 폰트가 디폴트로 바뀝니다.
그래서 메뉴 > Options > Save Option 를 선택해서 옵션정보를 저장해 줍니다.

이맥스를 종료합니다.

Emacs 설정 변경하기

이맥스를 실행하고, C-X C-F 를 입력 후 ~/.emacs 파일을 열어줍니다.

아래 내용을 입력해 줍니다.
아래 내용을 적용하기 위해 필요한 명령은 다음과 같습니다.

파일열기 : C-X C-F (Find)
파일저장 : C-X C-S (Save)
이맥스종료 : C-X C-C (Close)

;; -*- coding: utf-8 -*-

;; =============================================================================
;; 시작하기 전에
;; =============================================================================

;; - 메뉴 > Options > Use CUA Keys 체크
;; - 메뉴 > Options > Show/Hide > Tool-bar 체크해제
;; - 메뉴 > Options > Set Default Font
;; - 메뉴 > Options > Save Options
;; - C-x C-c 로 이맥스를 종료 후 재실행한다.

;; =============================================================================
;; 패키지 시스템(MELPA)
;; =============================================================================

(require 'package)

;; 패키지 사이트(org, melpa) 추가
;; (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

;; 패키지 시스템 초기화
(package-initialize)

(defalias 'lp 'list-packages)

;; =============================================================================
;; use-package
;;
;; 샘플코드
;; (use-package helm
;;   :ensure t                                ;; 패키지가 설치 안되어 있으면 설치
;;   :init                                    ;; 패키지 로딩 전 실행
;;   (add-hook 'after-init-hook 'helm-mode)
;;   :config                                  ;; 패키지 로딩 후 실행
;;   (helm-autoresize-mode 1))
;; =============================================================================

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(require 'use-package)

;; =============================================================================
;; 기본 설정
;; =============================================================================

(add-to-list 'load-path (expand-file-name "~/my-package"))

;; 튜토리얼 메시지 없애기
(setq inhibit-startup-message t)

;; 상태표시줄에 가로 세로 위치 표시
(column-number-mode t)
(line-number-mode t)

;; yes/no 입력 대신 y/n 입력하도록 변경
(fset 'yes-or-no-p 'y-or-n-p)

;; remove all trailing space when you save
(add-hook 'write-file-hooks
   'delete-trailing-whitespace)

;; 미니버퍼 히스토리를 저장한다.
(savehist-mode 1)

;; 대응하는 괄호 자동입력
(when (>= emacs-major-version 24)
  (electric-pair-mode 1))

;; 윈도우 제목 설정
(setq frame-title-format "Emacs - %b")
(setq icon-title-format "Emacs - %b")

;; 커서가 깜빡임 중단 안하기
(setq blink-cursor-blinks 0)

;; 자동 줄바꿈 안하기
(setq-default truncate-lines 1)

;; 백업파일 위치 지정
(setq backup-directory-alist '(("" . "~/.emacs.d/emacs-backup")))

;; 도움말 표시기능 사용한함
(setq global-eldoc-mode nil)

;; =============================================================================
;; 기본키 변경
;;
;; C-a (라인 맨 처음으로 이동 => 전체 선택)
;; C-e (라인 끝으로 이동 => 현재 라인 삭제)
;; C-f (커서 오른쪽으로 이동 => 검색)
;; C-s (검색 => 저장)
;; <F1> (도움말 => 현재창 하나만 남기기)
;; C-l (버퍼 내 커서이동 => 라인 이동)
;; =============================================================================

;; select all
(define-key global-map (kbd "C-a") 'mark-whole-buffer)

;; DELETE LINE
(defun delete-whole-line ()
  "delete whole line"
  (interactive)
  (delete-region (line-beginning-position) (line-end-position))
  (if (>= (point-max) (point))
      (delete-char 1)))
(define-key global-map (kbd "C-e") 'delete-whole-line)

;; 증가검색 단축키 변경(isearch)
(define-key global-map (kbd "C-f") 'isearch-forward)

;; 증가검색 단축키 변경(isearch)
(add-hook 'isearch-mode-hook
   (lambda ()
     (define-key isearch-mode-map (kbd "C-f") 'isearch-repeat-forward)
     (define-key isearch-mode-map (kbd "C-v") 'isearch-yank-kill)))

;; 저장하기 단축키 변경(save-buffer)
(global-set-key (kbd "C-s") 'save-buffer)

;; 현재 창만 남기고 다른 창 모두 닫기
(define-key global-map (kbd "<f1>") 'delete-other-windows)

;; goto-line
(define-key global-map (kbd "C-l") 'goto-line)

;; =============================================================================
;; 나만의 키 설정
;; =============================================================================

;; M-x 대용
(global-set-key (kbd "<f8>") 'execute-extended-command)

;; 현재 창 닫기
(define-key global-map (kbd "C-x c") 'kill-this-buffer)

;; 현재파일의 인코딩 변경
(global-set-key (kbd "C-c u") (lambda() (interactive) (set-buffer-file-coding-system 'utf-8) (message "Encoding changed to UTF-8")))
(global-set-key (kbd "C-c k") (lambda() (interactive) (set-buffer-file-coding-system 'cp949) (message "Encoding changed to CP949")))

;; ============================================================================
;; SMART HOME KEY
;; ============================================================================
(defun smart-beginning-of-line ()
  "Move point to first non-whitespace character or beginning-of-line."
  (interactive "^") ; Use (interactive "^") in Emacs 23 to make shift-select work
  (let ((oldpos (point)))
    (back-to-indentation)
    (and (= oldpos (point))
         (beginning-of-line))))

;; CUA 모드에서 Shift Home 이 정상적으로 작동하게 설정
;;(put 'smart-beginning-of-line 'CUA 'move)

(global-set-key (kbd "<home>") 'smart-beginning-of-line)

;; ============================================================================
;; 최근 열었던 파일 가져오기
;; ============================================================================

(recentf-mode 1)

;; 최근열었던 파일 1200까지 저장하기
(setq recentf-max-saved-items 1200)

;; 제외할 파일
(add-to-list 'recentf-exclude "Temporary Internet Files")
(add-to-list 'recentf-exclude "/.emacs.d/recentf")

;; 자동 저장기능 활성화
;; (setq recentf-auto-save-timer
;;   (run-with-idle-timer 60 t 'recentf-save-list))

(global-set-key [f12] 'recentf-open-files)

;; ============================================================================
;; 상태표시줄에 디렉토리를 포함한 파일명 표시
;; ============================================================================

(setq-default mode-line-buffer-identification
  (list 'buffer-file-name
    (propertized-buffer-identification "%12f")
    (propertized-buffer-identification "%12b")))

(add-hook 'dired-mode-hook
  (lambda ()
    ;; TODO: handle (DIRECTORY FILE ...) list value for dired-directory
    (setq mode-line-buffer-identification
      ;; emulate "%17b" (see dired-mode):
      '(:eval
        (propertized-buffer-identification
          (if (< (length default-directory) 17)
            (concat default-directory
              (make-string (- 17 (length default-directory))
                ?\s))
            default-directory))))))

;; ============================================================================
;; 단축명령
;; ============================================================================

(defalias 'qrr 'query-replace-regexp)
(defalias 'qr 'query-replace)

(defalias 'sh 'shell)

(defalias 'eb 'eval-buffer)
(defalias 'er 'eval-region)
(defalias 'ed 'eval-defun)

;; ============================================================================
;; Only on Windows-NT Emacs
;; ============================================================================

;; 이맥스 서버모드 활성화
(if (eq system-type 'windows-nt)
  (server-start)
  (message "* Running with server"))

;; ============================================================================
;; 커서위치 저장하기
;; ============================================================================

;; 파일 편집 위치 기억
(if (< emacs-major-version 25)
    (progn
      (require 'saveplace)
      (setq-default save-place t))
  (save-place-mode 1))

;; ============================================================================
;; 선택 영역 검색
;; ============================================================================

(defvar search-selection-last-searched-string nil)

(defun search-selection-or-last-searched (direction)
  "search for selected or last searched text"
  (let ((search-str search-selection-last-searched-string))
 (when (region-active-p)
   (setq search-str (buffer-substring (region-beginning) (region-end)))
   (setq search-selection-last-searched-string search-str))
 (if search-str
  (cond ((eq direction 'forward)
      (when (search-forward search-str nil t 1)
     (deactivate-mark)
     (setq found t)
     (set-mark (- (point) (length search-str)))))
     ((eq direction 'backward)
      (when (search-backward search-str nil t 1)
     (deactivate-mark)
     (setq found t)
     (set-mark (+ (point) (length search-str)))))
     (t
      (beep)
      (message "Unknown error.")))
   (beep)
      (message "No keyword for search."))))

(define-key global-map (kbd "<f3>") (lambda() (interactive) (search-selection-or-last-searched 'forward)))
(define-key global-map (kbd "C-<f3>") (lambda() (interactive) (search-selection-or-last-searched 'backward)))

;; ============================================================================
;; 버퍼 선택 툴
;; ============================================================================

(require 'bs)

(global-set-key [C-tab] 'bs-show)

;; (setq bs-default-configuration "all")
(setq bs-default-configuration "files-and-scratch")

(defun my-bs--get-modification-time-string (_start-buffer _all-buffers)
  "Return last modified time of file"
  (let ((file (buffer-file-name)))
    (if (and file (listp (visited-file-modtime)))
 (if (eq (car (visited-file-modtime)) -1)
     (string)
   (format-time-string "%Y-%m-%d %H:%M:%S" (visited-file-modtime)))
      (string))))

(setq bs-attributes-list
      '((""       1   1 left  bs--get-marked-string)
 ("M"      1   1 left  bs--get-modified-string)
 ("R"      2   2 left  bs--get-readonly-string)
 ("Buffer" 50 50 left  bs--get-name)
 (""       2   2 left  "  ")
 ("Size"   8   8 right bs--get-size-string)
 (""       2   2 left  "  ")
 ("Last Modified"   19   19 left my-bs--get-modification-time-string)
 (""       2   2 left  "  ")
 ("Mode"   20 20 left bs--get-mode-name)
 (""       2   2 left  "  ")
 ("File"   20 20 left  bs--get-file-name)))

;; =============================================================================
;; paste-and-indent
;; =============================================================================

(defun paste-and-indent ()
  (interactive)
  (if (and cua-delete-selection (region-active-p))
      (cua-delete-region))
  (yank)
  (indent-region (save-excursion (exchange-point-and-mark) (point)) (point)))

(global-set-key "\C-y" 'paste-and-indent)

;; =============================================================================
;; MS Windows 입력기 사용않함
;; 필요 : AutoHotkey, https://www.skyer9.pe.kr/wordpress/?p=5001
;; =============================================================================

(set-language-environment "Korean")
(setq default-input-method "korean-hangul")
(global-set-key (kbd "<S-SPC>") 'toggle-input-method)
;; (global-set-key (kbd "<Hangul>") 'toggle-input-method)
;; (global-set-key [(kana)] 'toggle-input-method)
(global-set-key [(kanji)] 'hangul-to-hanja-conversion)

;; =============================================================================
;; 북마크
;; =============================================================================

;; 북마크 설정시 자동저정
(setq bookmark-save-flag 1)

(global-set-key [f9] 'bookmark-bmenu-list)
(global-set-key [C-f9] 'bookmark-set)

;; =============================================================================
;; auto-complete
;; (필요 : melpa, auto-complete)
;; =============================================================================

(use-package auto-complete
  :ensure t)

(require 'auto-complete-config)

;; 자동완성 활성화
(global-auto-complete-mode t)

;; 2글자 입력시 자동완성 시작
(setq ac-auto-start 2)

;; 0.1 초 후 목록 표시함
(setq ac-auto-show-menu 0.1)

(ac-config-default)

;; TAB 키 누르면 자동완성 시작
(ac-set-trigger-key "TAB")

;; 활성화할 모드 추가(M-x major-mode RET)
(add-to-list 'ac-modes 'sql-mode)
(add-to-list 'ac-modes 'text-mode)

;; =============================================================================
;; yasnippet
;; (필요 : melpa, yasnippet)
;; =============================================================================

(use-package yasnippet
  :ensure t)

;; yasnippet 활성화
(yas-global-mode 1)

;; Remove Yasnippet's default tab key binding
(define-key yas-minor-mode-map (kbd "<tab>") nil)

(define-key yas-minor-mode-map (kbd "C-c y") 'yas-expand)

;; prog mode
(add-hook
 'prog-mode-hook
 (lambda ()
   (setq ac-sources
         (append '(ac-source-yasnippet) ac-sources))))

;; =============================================================================
;; cursor-chg
;; (필요 : https://www.emacswiki.org/emacs/cursor-chg.el)
;; =============================================================================

(require 'cursor-chg)

(change-cursor-mode 1)

;; 기본 커서 색상
;; (setq curchg-default-cursor-color "Black")

;; 한글 입력시 커서 색상
;;(setq curchg-input-method-cursor-color "Red")

;; 기본 커서 모양
(setq curchg-default-cursor-type 'bar)

;; 덮어쓰기 또는 read-only 버퍼일 때 커서 모양
(setq curchg-overwrite/read-only-cursor-type 'box)

;; =============================================================================
;; Visual bookmark
;; (필요 : MELPA, bm)
;; =============================================================================

(use-package bm
  :ensure t)

;; M$ Visual Studio key setup.
(global-set-key (kbd "<C-f2>") 'bm-toggle)
(global-set-key (kbd "<f2>")   'bm-next)
(global-set-key (kbd "<S-f2>") 'bm-previous)

;; =============================================================================
;; MinGW 설정
;; (필요 : http://www.mingw.org/)
;; 추가로 ~/.bashrc 에 패스를 다음과 같이 추가해 주어야 한다.
;; export PATH=/bin:/usr/bin:$PATH
;; =============================================================================

(setq shell-file-name "bash.exe")
(setq explicit-shell-file-name "C:/MinGW/msys/1.0/bin/bash.exe")
(setq exec-path (cons "C:/MinGW/msys/1.0/bin/" exec-path))

;; =============================================================================
;; browse-kill-ring
;; (필요 : MELPA, browse-kill-ring)
;; =============================================================================

(use-package browse-kill-ring
  :ensure t)

;; 여러 라인의 복사본을 한줄로 표시(separator 표시 않함)
(setq browse-kill-ring-display-style 'one-line)

;; 복사본 추가시 중복되는 복사본 삭제(browse-kill-ring 에서만 작동한다.)
(setq browse-kill-ring-no-duplicates t)

;; 중복되는 복사본 표시않함
(setq browse-kill-ring-display-duplicates nil)

;; 가장 최근 중복 복사본 표시
(setq browse-kill-ring-display-leftmost-duplicates t)

;; 최대 60글자만 표시
(setq browse-kill-ring-maximum-display-length 120)

;; 미리보기 표시
(setq browse-kill-ring-show-preview t)

;; 종료시 browse-kill-ring 창 닫기
(setq browse-kill-ring-quit-action 'save-and-restore)

;; 복사 목록 숫자 늘리기(디폴트 60개)
(setq kill-ring-max 200)

;; 속성은 제외하고 복사한다.(색상 등)
(setq browse-kill-ring-depropertize t)

(global-set-key [f7] 'browse-kill-ring)

;; =============================================================================
;; prog mode 설정하기(emacs 24+ only)
;; =============================================================================

(add-hook 'prog-mode-hook
  (lambda ()
    ;; 들여쓰기 할 때 실제 탭문자 입력
    (setq indent-tabs-mode t)
    ;; 탭 사이즈 4
    (setq tab-width 4)
    ;; 대응하는 괄호 표시
    (show-paren-mode t)
    ;; 엔터 입력시 들여쓰기
    (local-set-key (kbd "RET") 'newline-and-indent)
    ))

;; =============================================================================
;; elisp
;; =============================================================================

(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            (setq indent-tabs-mode nil)
            (setq tab-width 2)))

;; =============================================================================
;; Web Mode
;; (필요 : MELPA, web-mode)
;; =============================================================================

(use-package web-mode
  :ensure t)

(add-to-list 'auto-mode-alist '("\\.jsp\\'"   . web-mode))
(add-to-list 'auto-mode-alist '("\\.asp\\'"   . web-mode))
(add-to-list 'auto-mode-alist '("\\.php\\'"   . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\\'"   . web-mode))

(setq web-mode-engines-alist
      '(("asp" . "\\.asp\\'")))

(setq web-mode-enable-auto-pairing nil)
(setq web-mode-script-padding 0)
(setq web-mode-style-padding 0)

;; (defun my-web-mode-hook ()
;;   (setq web-mode-enable-auto-pairing nil)
;;   (electric-indent-local-mode -1))

;; (add-hook 'web-mode-hook  'my-web-mode-hook)

;; =============================================================================
;; 커서 위치 대소문자 변환
;; =============================================================================

(defun my-upcase-char-or-region ()
  "change char or selected region to upper case."
  (interactive)
  (if (region-active-p)
      (progn
        (upcase-region (region-beginning) (region-end))
        (setq deactivate-mark nil))
    (upcase-region (point) (+ (point) 1))))

(defun my-downcase-char-or-region ()
  "change char or selected region to lower case."
  (interactive)
  (if (region-active-p)
      (progn
        (downcase-region (region-beginning) (region-end))
        (setq deactivate-mark nil))
    (downcase-region (point) (+ (point) 1))))

(global-set-key (kbd "<f5>") 'my-upcase-char-or-region)
(global-set-key (kbd "C-<f5>") 'my-downcase-char-or-region)

;; =============================================================================
;; zenburn-theme
;; (필요 : MELPA, zenburn-theme)
;; =============================================================================

(use-package zenburn-theme
  :ensure t)

(load-theme 'zenburn t)

;; (set-face-background hl-line-face "#222222")
;; (set-face-attribute 'region nil :background "#4169e1")

(set-face-attribute 'region nil :background "#4169E1")
(set-face-attribute 'isearch nil :background "#4169E1")
;; (set-face-background 'hl-line "MidnightBlue")

;; ;;(setq curchg-input-method-cursor-color "Red")

;; ;; (setq curchg-default-cursor-color "Red")

;; ;; ;;(set-face-attribute 'region nil :background "#666")
;; ;; ;;(set-face-attribute 'region nil :background "#4169e1")
;; (set-face-attribute 'region nil :background "#4169e1")
;; (set-background-color "#000000")
;; (set-face-background hl-line-face "#222222")

;; ============================================================================
;; 윈도우 위치 & 사이즈 설정(GUI 버전)
;; ============================================================================

;; ;; 시작시 화면크기 최대로
;; (add-to-list 'default-frame-alist '(fullscreen . maximized))

;; 이맥스 프래임 최대화
(when (>= emacs-major-version 24)
  (toggle-frame-maximized))

;; ============================================================================
;; 폰트에서 bold 를 모두 없앤다.
;; ============================================================================

(mapc
 (lambda (face)
        (when (eq (face-attribute face :weight) 'bold)
          (set-face-attribute face nil :weight 'normal)))
 (face-list))

(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.
 '(cua-mode t nil (cua-base))
 '(package-selected-packages '(use-package))
 '(tool-bar-mode nil))
(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.
 '(default ((t (:family #("굴림체" 0 3 (charset cp949)) :foundry "outline" :slant normal :weight normal :height 90 :width normal)))))

Emacs 아이콘 생성하기

이맥스를 실행하면 도스창도 동시에 뜨기에, 도스창 없이 이맥스를 실행해 봅니다.

bin 폴더에 launch-emacs-client.vbs 라는 이름의 파일을 생성하고,
아래 내용을 입력합니다.

Set objShell = WScript.CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")

If WScript.Arguments.Count = 1 Then

  strComputer = "."

  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

  Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")

  Dim isRunning
  isRunning = False

  For Each objItem in colItems
    If InStr(objItem.CommandLine, "emacs.exe") Then
      isRunning = True
    End If
  Next

  If isRunning Then
    objShell.Run(fso.GetParentFolderName(WScript.ScriptFullName) & "/emacsclientw.exe -n """ & WScript.Arguments(0) & """")
  Else
    objShell.Run(fso.GetParentFolderName(WScript.ScriptFullName) & "/runemacs.exe """ & WScript.Arguments(0) & """")
  End If

Else
  objShell.Run(fso.GetParentFolderName(WScript.ScriptFullName) & "/runemacs.exe")
End If

launch-emacs-client.vbs 를 실행하면 도스창없이 이맥스가 실행됩니다.

한영전환키 오류 수정하기

한영전환은 Shift-Space 로 전환할 수 있지만,
한영전환키는 이상하게 오작동합니다.

https://www.skyer9.pe.kr/wordpress/?p=5001 를 참조해서 오류를 수정할 수 있습니다.

답글 남기기