Emacs の標準のインデント動作を変更したい -- namespace ではインデントしたくないんだ! --

問題点

namespace の {} 内でインデントしてしまう。

namespace My {
    namespace World {
        void func()
        {
            // ...
        }
    }
}

namespace はネストすることも多いし、インデントしたくないなあ……。 例えばこんな感じで…。

namespace My {
namespace World {

void func()
{
    // ...
}

} // End of namespace World
} // End of namespace My

さらにもともとインデントしているファイルは 勝手にインデントを変更せず、そのままにしたいなあ…

namespace Their {
    namespace World {
        void func()
        {
            // ...
        }
    }
}

処方箋

C-c C-s (c-show-syntactic-information) を実行すると、カーソルがある位置のインデント情報が表示される。 たとえば

namespace My {
| <== ここにカーソル
}

ここにカーソルを置いてC-c C-s を実行すると、

Syntactic analysis: ((innamespace 52) (topmost-intro 52))

などと表示される。innamespace というのを覚えておく。

その後 C-c C-o (c-set-offset) で innamespace のインデント設定を変更する。

C-c C-o
Syntactic symbol to change: innamespace    # innamespace と入力
innamespace offset (default +): 0          # 0 と入力

などとする。これで namespace 内で自動的にインデントしなくなる。(すでにインデントされている行でTABを打つなどするとインデントがずれるので、元のコードをそのままにしたいときは注意が必要)

これを init.el に書いておけばOK。下記のように。

(defunc my-c-mode-common-hook ()
    ;; styleの選択
    (c-set-style "stroustrup")

    ;; インデント規則 (c-set-style の後に設定する必要がある) 
    (c-set-offset 'innamespace 0)
)
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

注意点としては、 c-set-offset の指定は c-set-style の後にやらないといけないこと。先に書くと、c-set-style の設定で上書きされて消えてしまう。

旧処方箋(2020年現在、これだと動かなかった c-set-style との順番のせいかもしれない)

Emacs の設定を変更。c-offset-alist の innamespace などの設定を (c-lineup-dont-change) に変える。

Customize で C Offsets Alistを変える。

  1. M-x customize
    • Programming で Enter
    • Language で Enter
    • C を選択して Enter
    • C Offsets Alist を選択して Enter
    • (M-x customize-apropos で c offsets alist を検索してもいける)
  2. C Offsets Alist の 一覧が開く
  3. 下記の設定値の左のチェックボックスを ON にして…
    • namespace-open
    • namespace-close
    • innamespace
  4. 値を (c-lineup-dont-change) に書き換える
  5. State ボタンをおして…
  6. Save for Future Sessions を実行 ==> .emacs とかに設定が書かれる。

以上。

おまけ

  • extern "C" {} とかもインデントしたくない場合は
    • extern-lang-open
    • extern-lang-close
    • inextern-lang
  • も同じ設定にする。

参考資料

TeraTerm 上で Emacs を動かすと utf8 の罫線が短くなる問題の処方箋

問題点

Utf8 の罫線(等)を表示するときに TeraTerm で変な変換をかけているらしい。 外国のひと向けに罫線の長さを半角にして表示している様子。 罫線を全角表示したいわれわれ古い日本人には必要ない設定のようだぞ。

処方箋

TERATERM.ini の設定を変更する

  • UnknownUnicodeCharacterAsWide を off ==> on に。(こっちはついでにやってみた)

  • UnicodeToDecSpMapping を 3 ==> 0 に。(こっちが問題の本質)

TERATERM.ini

; Unknown Unicode character handling
UnknownUnicodeCharacterAsWide=on

; Mapping of Unicode to DEC special character
;   The sum of following values:
;   1 : Box drawings (U+2500-U+257F)
;   2 : Bullet (U+2022)
;       Hyphenation point (U+2027)
;       Light shade (25%) (U+2591)
;       Medium shade (50%) (U+2592)
;       Dark shade (75%) (U+2593)
;       Black small square (U+25AA)
;       Black vertical rectangle (U+25AE)
;       Black verty small square (U+2B1D)
;   4 : Middle dot (U+00B7)
;       One dot leader (U+2024)
;       Bullet operator (U+2219)
UnicodeToDecSpMapping=0

設定をファイルに保存し、 TeraTerm を再起動し、 emacs -nw でファイルを開くと、 罫線が正しく表示された。

ご参考

  • =>TeraTerm設定ファイルの説明
  • ここ(↑)にある下記を参照。
  • 同じものは TeraTerm のヘルプからも見られます。

  • TeraTerm を C:\Program Files とか Windows の管理しているフォルダにインストールしている場合は、TERATERM.ini を管理者権限で開く必要あるかも。

  • Emacs ではこれで OK だった。しかし vi では表示は治ったけどカーソル移動が変。 vim なら動くかな(試してない)。たぶん Unicode の曖昧な文字幅の影響だろうね。

.emacs の utf8 設定

ちなみに Linux 上で動かすときは .emacs には下記の設定を入れている。 設定をしないと変な命令をターミナルに送るらしく、行ずれが起きていた。

(set-language-environment "Japanese")
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-buffer-file-coding-system 'utf-8)
(setq default-buffer-file-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(setq file-name-coding-system 'utf-8)

参考資料

git difftool で WinMerge を起動する方法 for Cygwin

cygwin なので cygpath での変換が必要。

$ git config --global diff.tool WinMerge
$ git config --global difftool.WinMerge.cmd \
"\"/cygdrive/c/Program Files (x86)/WinMerge/WinMergeU.exe\" \
-u \`cygpath -am \"\$LOCAL\"\` \`cygpath -am \"\$REMOTE\"\`"

$ git difftool -y
==> WinMerge で index と working tree を比較。

$ git add -u
$ git difftool --cached -y
==> HEAD と index を比較。

$ git difftool -y HEAD
==> HEAD と working tree を比較。
  • HEAD: git commit したの。
  • index: git add したの。まだ commit していないの。
  • worikng tree: ふつうに作業してるディレクトリツリーにあるの。

dot.bashrc の設定

dot.bashrc の設定。

alias ls='ls --show-control-char'
alias ll='ls -l'
alias lld='ls -ld'
alias lla='ls -la'

#alias e='emacs-w32.exe -r'
#alias e='emacs'
alias e='/app/cygwin/emacs/bin/emacs'

export LANG=ja_JP.UTF-8
export LC_ALL=ja_JP.UTF-8

# man の出力を均等割り付けしない
export MANOPT=--no-justification

# gnupack の /app/cygwin/local/bin を PATH に追加しておく
# (/etc/fstab を編集し C:/gnupack/gnupack_devel-13.06-2015.11.08/app を /app にマウントしている)
# /usr/local にマウントしたので PATH いらない。
#export PATH=/app/cygwin/local/bin:$PATH

# 自分用のPATH
export PATH=~/bin:$PATH


# dircolors の設定 (dircolors の出力をセット)
LS_COLORS='rs=0:di=01;34:ln=01;36:...:*.xspf=00;36:';
export LS_COLORS

dot.emacs の設定

新しいの

;;--------------------------------------------------
;; Load Path
;;--------------------------------------------------

;; Added by Package.el.  This must come before configurations of
;; installed packages.  Don't delete this line.  If you don't want it,
;; just comment it out by adding a semicolon to the start of the line.
;; You may delete these explanatory comments.
(package-initialize)

(setq load-path
      (append
       (list (expand-file-name "~/mylisp"))
       load-path))

;;--------------------------------------------------
;; theme
;;--------------------------------------------------
(load-theme 'zenburn t)
;;(load-theme 'hc-zenburn t)

;;--------------------------------------------------
;; Package
;;--------------------------------------------------
(require 'package)
;; melpa を追加
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)

(package-initialize)

;;--------------------------------------------------
;; Language Settings
;;--------------------------------------------------
;; set language as Japanese
(set-language-environment 'Japanese)
;; coding UTF8
(set-language-environment  'utf-8)
(prefer-coding-system 'utf-8)


;;--------------------------------------------------
;; Key bindings
;;--------------------------------------------------
;; C-z
(global-set-key "\C-z" 'undo)
;; C-x C-z
(global-set-key "\C-x\C-z" 'suspend-emacs)
;; C-h
;;(global-set-key "\C-h" 'delete-backward-char)
;; help
;;(global-set-key "\C-c\C-h" 'help-command)
;; comment out
;;(global-set-key "\C-c;" 'comment-dwim)
;; move window
;;(global-set-key "\C-t" 'other-window)
(global-set-key [f9] 'other-window)
;; move buffer
(global-set-key [f11] 'previous-buffer)
(global-set-key [f12] 'next-buffer)

;; next-error (default)
;;(global-set-key "\M-gn" 'next-error)
;; prev-error (default)
;;(global-set-key "\M-gp" 'prev-error)

;; open header or #include file.
(global-set-key "\C-c\C-h" 'ff-find-other-file)


;;--------------------------------------------------
;; Mouse
;;--------------------------------------------------
(xterm-mouse-mode t)



;;--------------------------------------------------
;; Preference
;;--------------------------------------------------
;; デフォルトの起動時のメッセージを表示しない
(setq inhibit-startup-message t)

;; メニューバーの非表示
(menu-bar-mode -1)

;; ツールバーの非表示
(tool-bar-mode -1)

;; 分割数を制限
(setq split-height-threshold nil)
(setq split-width-thireshold nil)

;; Disk上のファイルが変更されたらそれを読み込む。
;;(setq global-auto-revert-mode 1)

;; font-lock mode いるかね? 遅くならない?
;;(global-font-lock-mode t)

;; ファイルの末尾は改行になるのを強制
;;(setq require-final-newline t)

;; next-line でバッファの最後に改行を入れない(今はデフォルトで nil なので設定不要)
;;(setq next-line-add-newlines nil)

;; Emacsの終了が遅くなるので Backup は作らない
(setq backup-inhibited t)
(setq delete-auto-save-files t)
(setq make-backup-files nil)
(setq auto-save-default nil)

;; でも編集位置は記憶しておく。終了が遅くなるけど
(save-place-mode 1)

;; 列の番号を表示
(column-number-mode t)

;; 行番号を表示
(global-linum-mode t)
(setq linum-format "%5d ")
;;(set-face-attribute 'linum nil :foreground "gray55" :background "gray20")

;; 関数名を表示
(which-function-mode t)

;;(setq-default scroll-step 0)
;; 右端で折り返さない
;;(setq-default truncate-lines t)
;; C-x 3 などの縦分割ウィンドウで右端で折り返さない
;;(setq-default truncate-partial-width-windows t)

;; コンパイル時のウィンドウの高さ
(setq-default compilation-window-height 10)




;; Tabにスペース4つを利用
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)

;; 1行ごとにスクロールする (1 だとたまにジャンプするので巨大数を指定する)
(setq scroll-conservatively 10000)

;; スクロール時にカーソル位置を保持
(setq scroll-preserve-screen-position t)

;; スクロールの上下マージン
(setq-default scroll-margin 1)

;; カーソル行を一瞬光らせる
(beacon-mode 1)

;; カーソル行をハイライト
;; customize-face で常に hl-face がデフォルトになったりするので使わない
;; (GLOBAL-hl-line-mode nil)

;; BS や Delete キーでリージョン内の文字を削除
(delete-selection-mode 1)

;; selection hilighting (デフォルトで t なので設定不要)
;;(setq-default transient-mark-mode t)

;; 対応する括弧を光らせる
(show-paren-mode t)

;; 括弧を自動で補完する
(electric-pair-mode 1)

;; 行頭の C-k で改行も kill する
(setq kill-whole-line t)

;; 最近開いたファイルが File メニュー内にあらわさる
;; ivy 使うのでいらない
;;(recentf-mode)


;;--------------------------------------------------
;; C-Mode Common Hook
;;--------------------------------------------------
(defun my-c-mode-common-hook ()
  ;; ggtags on
  (ggtags-mode t)

  ;; 行コメント開始位置
  (setq   comment-column 48)

  ;; コメント形式
  ;; (setq comment-start "/* ")
  ;; (setq comment-end " */")
  ;; (setq comment-style (quote aligned))

  ;; case sensitive search
  ;;(setq case-fold-search nil)

  ;; Backcpaceでタブを空白に変換しない
  ;; (setq c-backspace-function 'backward-delete-char)

  ;; hungry-delete
  ;;(setq c-hungry-delete-key t)

  ;; インデント情報の表示
  ;; (setq c-echo-syntactic-information-p t)

  ;; ワード単位の移動 camelCase に対応
  ;; (subword-mode)

  ;; styleの選択。いらないのでは? これが重くなく原因かな。
  ;;(c-set-style "stroustrup")

  ;; インデント規則 (c-set-style の後に設定する必要がある)
  (c-set-offset 'innamespace 0)
  (c-set-offset 'defun-block-intro +4)
  (c-set-offset 'statement-block-intro +4)
  )
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

;;--------------------------------------------------
;; ivy/counsel
;;--------------------------------------------------
(ivy-mode 1)

(setq enable-recursive-minibuffers t)
(setq ivy-use-virtual-buffers t)
(setq ivy-count-format "(%d/%d)")

;; 候補の表示行数最大値
(setq ivy-height (truncate (* (window-height) 0.5)))
;;(setq ivy-height 32)

;; 常に固定の行数を表示するかどうか
;;(setq ivy-fixed-height-minibuffer nil)

;; Keybindings
;;(global-set-key (kbd "M-x") 'counsel-M-x)
;;(global-set-key (kbd "C-x C-f") 'counsel-find-file)
(global-set-key (kbd "C-c c s") 'swiper)
(global-set-key (kbd "C-C C-r") 'ivy-resume)


;;--------------------------------------------------
;; counsel-gtags
;;--------------------------------------------------
(add-hook 'c-mode-hook 'counsel-gtags-mode)
(add-hook 'c++-mode-hook 'counsel-gtags-mode)

(with-eval-after-load 'counsel-gtags
  (define-key counsel-gtags-mode-map (kbd "C-c g b") 'counsel-gtags-go-backward)
  (define-key counsel-gtags-mode-map (kbd "C-c g f") 'counsel-gtags-go-forward)
  (define-key counsel-gtags-mode-map (kbd "C-]") 'counsel-gtags-dwim)
  (define-key counsel-gtags-mode-map (kbd "C-t") 'counsel-gtags-go-backward)
  )


;;--------------------------------------------------
;; 
;;--------------------------------------------------
(which-key-mode t)


;;--------------------------------------------------
;; Customize Settings
;;--------------------------------------------------
;; カスタマイズを保存するファイル
(setq custom-file "~/.emacs.d/customize_settings.el")
;; カスタマイズ用ファイルをロード
(load custom-file t)

古いの

dot.emacs

追加で使っているelispcygwin-mount.el, doxymacs.el と gtags.el くらい。

(global-set-key [delete] 'delete-char)
(global-set-key [kp-delete] 'delete-char)

;; open #include <...> file
(global-set-key "\C-c\C-h" 'ff-find-other-file)

;;(global-set-key [home] 'beginning-of-line)
;;(global-set-key [end] 'end-of-line)
;;(global-set-key [C-home] 'beginning-of-buffer)
;;(global-set-key [C-end] 'end-of-buffer)
;;(global-set-key [C-tab] 'bs-cycle-previous)
;;(global-set-key [C-S-iso-lefttab] 'bs-cycle-next)

;; C-z では、suspend-emacs関数が呼ばれるが、C-x C-zでも同じ
;; なので、C-zはUndoにする
(global-set-key "\C-z" 'advertised-undo)               ;; C-x u (Undo)

;;(global-set-key [find] 'overwrite-mode)                ;; PC Insert key
;;(global-set-key [insertchar] 'beginning-of-line)       ;; PC Home key
;;(global-set-key [prior] 'end-of-line)                  ;; PC End key
;;(global-set-key [deletechar] 'scroll-down)             ;; PC PageUp key
(global-set-key [find] 'beginning-of-line)             ;; PC Home key
(global-set-key [select] 'end-of-line)                 ;; PC End key
(global-set-key [insertchar] 'overwrite-mode)          ;; PC Insert key

;;(global-set-key [f3] 'delete-other-windows)

;; ビルド&エラー検索用 ビルド&エラー検索キーマップキーマップ
(global-set-key [f4] 'next-error)
(global-set-key [f14] 'previous-error) ;; f14 == Shift F4
(global-set-key [f5] 'compilation-mode)

;; カレントワードのmanを起動
(global-set-key  [f6]  (lambda () (interactive) (manual-entry (current-word))))
;;(setq manual-program "jmanx")

(global-set-key [f7] 'compile)
(global-set-key [f8] 'grep)

;; same as C-x o
(global-set-key [f9] 'other-window)

;; move buffer
(global-set-key [f11] 'bs-cycle-previous)
(global-set-key [f12] 'bs-cycle-next)


(global-set-key [mouse-4] 'scroll-down)
(global-set-key [mouse-5] 'scroll-up)


;; (cd "~/")

;; font-lock mode
(global-font-lock-mode t)

;; visual feedback on selections
(setq-default transient-mark-mode t)

;; last newline
(setq require-final-newline t)

;; not add lines
(setq next-line-add-newlines nil)

;;(setq backup-inhibited t)
;;(setq delete-auto-save-files t)
;;(setq make-backup-files nil)
;;(setq auto-save-default nil)

;; 列数を表示する
(column-number-mode t)

;; 左端に行数を表示する
(global-linum-mode t)

 ;; カーソルの点滅をやめる
(blink-cursor-mode 0)

;; カーソル行をハイライトする
;;(global-hl-line-mode t)

(setq kill-whole-line t)

(display-time)

(which-function-mode 1)

(recentf-mode)

;; 対応する括弧を光らせる
(show-paren-mode t)
;;(setq show-paren-style 'mixed)        ;; 対応する括弧が画面外のときだけ内容を色変え
;;(setq show-paren-style 'expression)     ;; 常に色変え
(set-face-background 'show-paren-match-face "blue") ;; "gray10")
(set-face-foreground 'show-paren-match-face "skyblue")  ;;"SkyBlue")

;; スペース、タブなどを可視化
;; コンソールだと化ける→;; (global-whitespace-mode 1)

;; スクロールは1行ごとに
(setq scroll-conservatively 10000)

;; シフト+矢印で範囲選択
;;(setq pc-select-selection-keys-only t)
;;(pc-selection-mode 1)

(setq default-tab-width 4)
;;(add-hook 'shell-mode-hook '(lamda () (setq tab-width 8))) ;; shellモードはタブ8でないと化けるらしい
(setq auto-mode-alist (cons '("\\.h\\'" . c++-mode) auto-mode-alist))

::(setq vc-default-back-end 'CVS)

;; (setq compile-command "date; gcc -g -Wall -o ")

(setq-default scroll-step 0)

;; 右端で折り返さない
;;(setq-default truncate-lines t)

;; C-x 3 などの縦分割ウィンドウで右端で折り返さない
;;(setq-default truncate-partial-width-windows t)

(setq-default compilation-window-height 10)

;;(setq frame-title-format (format "emacs@%s : %%f" (system-name)))
(setq-default frame-title-format "%b")

;; スクロール時にカーソル位置を保持
(setq scroll-preserve-screen-position t)

;; BS や Delete キーでリージョン内の文字を削除
(delete-selection-mode 1)

;; find file at point #include <stdio.h>とか開いてくれる
;; 従来のFindFindはC-u C-x C-Fとなる。
(ffap-bindings)
(setq ffap-c-path
      '("/usr/include"
        "/usr/include/c++/3.2"
        "/usr/local/include"
        "../include"))


(defun my-c-mode-common-hook ()
    ;; my customizations for all of c-mode and related modes

    ;; コンパイルのときに毎回訊きに来ない
    ;;(setq compilation-read-command nil)

    ;; compileのときに使うコマンド
    ;;(set (make-local-variable 'compile-command) "make -k -C ../Build")

    ;; 
    (setq   comment-column 48)

    ;; 先頭でのTabのみインデント処理する。Tab <==> M-i の入れ替えをするので不要
    ;; (setq c-tab-always-indent nil)

    ;; { の入力などで自動インデント処理
    ;; (setq c-auto-newline t)

    ;; 基本インデント量
    (setq c-basic-offset 4)

    ;; Tabは4
    (setq tab-width 4)

    ;; タブストップの位置
    (setq tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 156))

    ;; case sensitive
    ;;(setq case-fold-search nil)
    (setq case-fold-search t)

    ;; 後退の時タブをスペースに変換しない
    (setq c-backspace-function 'backward-delete-char)

    ;; インデント情報の表示
    (setq c-echo-syntactic-information-p t)

    ;; EnterとC-jの交換
    (local-set-key "\C-m" 'newline-and-indent)      ;; ReturnをC-jにする
    (local-set-key "\C-j" 'newline)                 ;; C-j をReturnにする

    ;; TabとM-iの交換
;   (local-set-key "\C-i" 'tab-to-tab-stop)         ;; Tabキーを普通のTabに
;   (local-set-key "\M-i" 'c-indent-command)        ;; M-iキーをインデントにする

    ;; if/for/whileなどの次の行はインデントはそのまま。
    (c-set-offset 'substatement-open    0)
    ;;(c-set-offset 'comment-intro      0)

    ;; 右端で折り返さない
    (setq truncate-lines t)                 ;; 右端で折り返さない cmd:toggle-truncate-lines
    (setq truncate-partial-width-windows t) ;; C-x 3など縦分割ウィンドウで右端で折り返さない

    ;; ワード単位の移動で camelCase に対応
;   (subword-mode)
    )

(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)



;;~/bak/にバックアップ作成
(setq backup-by-copying t)
(fset 'make-backup-file-name
      '(lambda (file)
          (concat (expand-file-name "~/bak/")
                  (file-name-nondirectory file))
         ))
(if (file-exists-p "~/bak/")
    (setq auto-save-list-file-prefix "~/bak/"))

(setq make-backup-files t)
(setq backup-directory-alist
      (cons (cons "\\.*$" (expand-file-name "~/bak"))
            backup-directory-alist))

;; かんたんなVersionControl
(setq version-control t)

;; 新しいものをいくつ残すか
(setq kept-new-versions 2)

;; 古いものをいくつ残すか
(setq kept-old-versions 2)

;; 尋ねずに削除
(setq delete-old-versions t)

;; 編集位置を記憶
(load "saveplace")
(setq-default save-place t)


;;ロードパスを追加
(setq load-path
      (append
       (list (expand-file-name "~/mylisp")) load-path))

;; 罫線lispの設定
(if window-system
    (autoload 'keisen-mode "keisen-mouse" "MULE 版罫線モード + マウス" t)
  (autoload 'keisen-mode "keisen-mule" "MULE 版罫線モード" t))



(require 'doxymacs)
(add-hook 'c-mode-common-hook 'doxymacs-mode)


(require 'gtags)

;; If you hope gtags-mode is on in c-mode then please add c-mode-hook to your
;; $HOME/.emacs like this.
;;
(setq c-mode-hook
    '(lambda ()
    (gtags-mode 1)
))

;; There are two hooks, gtags-mode-hook and gtags-select-mode-hook.
;; The usage of the hook is shown as follows.
;;
;; [Setting to reproduce old 'Gtags mode']
;;
;; (setq gtags-mode-hook
;;   '(lambda ()
;;      (setq gtags-pop-delete t)
;;      (setq gtags-path-style 'absolute)
;; ))
;;
;; [Setting to make 'Gtags select mode' easy to see]
;;
(setq gtags-select-mode-hook
  '(lambda ()
     (setq hl-line-face 'underline)
     (hl-line-mode 1)
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GNU GLOBAL(gtags)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;(autoload 'gtags-mode "gtags" "" t)
(setq gtags-mode-hook
      '(lambda ()
         (local-set-key "\M-t" 'gtags-find-tag)
         (local-set-key "\M-r" 'gtags-find-rtag)
         (local-set-key "\M-s" 'gtags-find-symbol)
         ;(local-set-key "\C-t" 'gtags-pop-stack)
         ))

(setq inhibit-startup-message t)        ; 開始メッセージを削除
(menu-bar-mode -1)                      ; メニューを消す
(tool-bar-mode -1)                      ; ツールバーを消す

;; region の色
(set-face-background 'region "SkyBlue")
(set-face-foreground 'region "black")

(if (boundp 'window-system)
    (setq initial-frame-alist
          (append (list
                   '(foreground-color . "azure3") ;; 文字が白
                   '(background-color . "black") ;; 背景は黒
                   '(border-color     . "black")
                   '(mouse-color      . "white")
                   '(cursor-color     . "white")
                   '(cursor-type      . box)
                   '(menu-bar-lines . 1)
                   ;'(vertical-scroll-bars . nil) ;;スクロールバーはいらない
                   ;;'(font . "MS Gothic 12")
                   '(font . "MS Gothic 9")
                   '(width . 120) ;; ウィンドウ幅
                   '(height . 50) ;; ウィンドウの高さ
                   '(top . 0) ;;表示位置
                   ;;'(left . 50) ;;表示位置
                   '(left . 0) ;;表示位置
                   )
                  initial-frame-alist)))
(setq default-frame-alist initial-frame-alist)

;;(require 'cygwin-mount)                   ; cygwin-mount
;;(cygwin-mount-activate)                   ; cygwin-mount


;; rubydb - ruby debugger
;;(autoload 'rubydb "rubydb3x" "ruby debug" t)




(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.
 '(comment-style (quote extra-line))
 '(ediff-make-buffers-readonly-at-startup t)
 '(ediff-split-window-function (quote split-window-horizontally))
 '(line-move-visual t))
(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.
 )

StoreBuffer(仮)

StoreBuffer とりあえずコンパイル通った版。

#include <stdio.h>
#include <string.h>
#include "type.h"
#include "util.h"
#include "Dmac.h"
#include "StoreBuffer.h"




#define MAX_STORE_BUFFER_NUM    4
#define MAX_LINE_NUM            32
#define MIN_LINE_SIZE           16




typedef struct STORE_BUFFER_T {
    UINT32                      buffer;         /* store buffer */
    UINT32                      capacity;       /* size of buffer in bytes */
    UINT32                      lineSize;       /* size of cache line in bytes */
    UINT32                      lineNum;        /* count of cache line */
    UINT32                      lineUsed;       /* count of used cache line */
    UINT32                      lineDict[MAX_LINE_NUM]; /* high bit: destination address.
                                                           low  bit: index of cache line.
                                                           The number of bits changes according to
                                                           the lineSize.
                                                           */
    UINT32                      destBeg;        /* begin address of destination */
    UINT32                      destEnd;        /* end address of destination (exclude this) */
    UINT8                       flag;           /* flag */
} STORE_BUFFER_T;

/* STORE_BUFFER_T.flag */
#define FLAG_USED               0x01
#define FLAG_PRELOAD            0x02



typedef struct STORE_BUFFER_WORK_T {
    STORE_BUFFER_T              storeBuffer[MAX_STORE_BUFFER_NUM];
} STORE_BUFFER_WORK_T;




PRIVATE STORE_BUFFER_WORK_T     sMtkStoreBufferWork;



#define work                    (&sMtkStoreBufferWork)
#define getItem(id)             (&work->storeBuffer[id])
#define checkID(id)             ((0 <= id) && (id < MAX_STORE_BUFFER_NUM))



PRIVATE UINT32 MostLeftHighBit(UINT32 data);
PRIVATE void* GetLine(STORE_BUFFER_T* self, void* dest);
PRIVATE UINT32 GetDict(STORE_BUFFER_T* self, void* dest);
PRIVATE UINT32* SearchDict(STORE_BUFFER_T* self, void* dest);
PRIVATE UINT32* AllocDict(STORE_BUFFER_T* self, void* dest);
PRIVATE void Preload(STORE_BUFFER_T* self, UINT32 dict);
PRIVATE void RotateMruDict(STORE_BUFFER_T* self, UINT32 index);
PRIVATE void FlushLruDict(STORE_BUFFER_T* self);
PRIVATE BOOL CheckDestRange(STORE_BUFFER_T* self, void* dest);
PRIVATE UINT32 WriteLine(STORE_BUFFER_T* self, void* line, const void* dest, const void* src, UINT32 size);
PRIVATE UINT32 FillLine(STORE_BUFFER_T* self, void* line, const void* dest, INT filler, UINT32 size);
PRIVATE void ShellSort(UINT32* arr, UINT32 num);
PRIVATE void JoinWrite(STORE_BUFFER_T* self);




void MtkInitializeStoreBuffer(void)
{
    memset(work, 0, sizeof(*work));
}

INT MtkCreateStoreBuffer(void* buffer, UINT32 capacity, UINT32 lineSize, void* destBeg, void* destEnd)
{
    INT id;
    STORE_BUFFER_T* sb;
    INT i;

    for (id = 0; id < MAX_STORE_BUFFER_NUM; ++id) {
        sb = getItem(id);
        if (MTK_BTST(sb->flag, FLAG_USED) == 0) {
            break;
        }
    }
    if (id >= MAX_STORE_BUFFER_NUM) {
        return INVALID_STORE_BUFFER_ID;
    }

    lineSize = MostLeftHighBit(lineSize);
    lineSize = MTK_MIN(lineSize, capacity);
    lineSize = MTK_MAX(lineSize, MIN_LINE_SIZE);

    sb->buffer   = (UINT32) buffer;
    sb->capacity = capacity;
    sb->lineSize = lineSize;
    sb->lineNum  = capacity / lineSize;
    sb->lineNum  = MTK_MIN(sb->lineNum, MAX_LINE_NUM);
    sb->lineUsed = 0;
    for (i = 0; i < MAX_LINE_NUM; ++i) {
        sb->lineDict[i] = i;                    /* set cache line id into low bits */
    }
    sb->destBeg  = (UINT32) destBeg;
    sb->destEnd  = (UINT32) destEnd;
    sb->flag     = FLAG_USED;

    return id;
}

void MtkDestroyStoreBuffer(INT id)
{
    STORE_BUFFER_T* sb;

    if (! checkID(id)) {
        return;
    }

    MtkFlushStoreBuffer(id);

    sb = getItem(id);

    MTK_BCLR(sb->flag, FLAG_USED);
}

BOOL MtkSetPreload(INT id,  BOOL preload)
{
    STORE_BUFFER_T* sb;

    if (! checkID(id)) {
        return FALSE;
    }

    sb = getItem(id);

    if (preload) {
        MTK_BSET(sb->flag, FLAG_PRELOAD);
    }
    else {
        MTK_BCLR(sb->flag, FLAG_PRELOAD);
    }

    return TRUE;
}

BOOL MtkWriteStoreBuffer(INT id, void* dest, const void* src, UINT32 size)
{
    STORE_BUFFER_T* sb;
    void* line;
    UINT32 written;

    if (! checkID(id)) {
        return FALSE;
    }

    sb = getItem(id);

    if (! CheckDestRange(sb, dest)) {
        return FALSE;
    }

    do {
        line    = GetLine(sb, dest);
        written = WriteLine(sb, line, dest, src, size);
        dest    = (      void*)((UINT32)dest + written);
        src     = (const void*)((UINT32)src  + written);
        size   -= written;
    } while (size);

    return TRUE;
}

BOOL MtkFillStoreBuffer(INT id, void* dest, INT filler, UINT32 size)
{
    STORE_BUFFER_T* sb;
    void* line;
    UINT32 written;

    if (! checkID(id)) {
        return FALSE;
    }

    sb = getItem(id);

    if (! CheckDestRange(sb, dest)) {
        return FALSE;
    }

    do {
        line    = GetLine(sb, dest);
        written = FillLine(sb, line, dest, filler, size);
        dest    = (      void*)((UINT32)dest + written);
        size   -= written;
    } while (size);

    return TRUE;
}

BOOL MtkFlushStoreBuffer(INT id)
{
    STORE_BUFFER_T* sb;

    if (! checkID(id)) {
        return FALSE;
    }

    sb = getItem(id);

    /* lineDict[]をソートする */
    ShellSort(sb->lineDict, sb->lineUsed);

    /* destが連続している領域は一気に出力 */
    JoinWrite(sb);

    /* preload を ON にする */
    MTK_BSET(sb->flag, FLAG_PRELOAD);

    return TRUE;
}








PRIVATE UINT32 MostLeftHighBit(UINT32 data)
{
    UINT32 tester = 0x80000000;
    while (tester) {
        if (MTK_BTST(data, tester)) {
            return tester;
        }
        tester >>= 1;
    }
    return 0;
}

PRIVATE void* GetLine(STORE_BUFFER_T* self, void* dest)
{
    UINT32 dict = GetDict(self, dest);
    UINT32 mask = ~(self->lineSize - 1);
    UINT32 index;
    UINT32 line;

    index = MTK_BTST(dict, ~mask);
    line  = self->buffer + self->lineSize * index;

    return (void*)line;
}

PRIVATE UINT32 GetDict(STORE_BUFFER_T* self, void* dest)
{
    UINT32* dict;

    dict = SearchDict(self, dest);
    if (! dict) {
        dict = AllocDict(self, dest);
        if (! dict) {
            FlushLruDict(self);
            dict = AllocDict(self, dest);
        }
    }

    return *dict;
}

PRIVATE UINT32* SearchDict(STORE_BUFFER_T* self, void* dest)
{
    UINT32 mask = ~(self->lineSize - 1);
    INT i;

    /* serch backward for search MRU entry first */
    for (i = self->lineUsed - 1; i >= 0; --i) {
        if (MTK_BTST((UINT32)dest, mask) == MTK_BTST(self->lineDict[i], mask)) {
            RotateMruDict(self, i);
            return &self->lineDict[self->lineUsed - 1];
        }
    }

    return NULL;
}

PRIVATE UINT32* AllocDict(STORE_BUFFER_T* self, void* dest)
{
    UINT32 mask = ~(self->lineSize - 1);
    UINT32 i;

    if (self->lineUsed >= self->lineNum) {
        return NULL;
    }

    i = self->lineUsed++;

    /* @note low bit(cache line id) was saved in lineDict[i]*/
    MTK_BCLR(self->lineDict[i], mask);
    MTK_BSET(self->lineDict[i], MTK_BTST((UINT32)dest, mask));

    if (MTK_BTST(self->flag, FLAG_PRELOAD)) {
        Preload(self, self->lineDict[i]);
    }

    return &self->lineDict[i];
}

PRIVATE void Preload(STORE_BUFFER_T* self, UINT32 dict)
{
    UINT32 mask = ~(self->lineSize - 1);
    UINT32 dest;
    UINT32 index;
    UINT32 line;

    dest  = MTK_BTST(dict, mask);
    index = MTK_BTST(dict, ~mask);
    line  = self->buffer + self->lineSize * index;

    ReadDmac((void*)line, (void*)dest, self->lineSize);
}

PRIVATE void RotateMruDict(STORE_BUFFER_T* self, UINT32 index)
{
    UINT32 tmp = self->lineDict[index];
    UINT32 i;

    for (i = index; i < self->lineNum - 1; ++i) {
        self->lineDict[i] = self->lineDict[i + 1];
    }
    self->lineDict[self->lineNum - 1] = tmp;
}

PRIVATE void FlushLruDict(STORE_BUFFER_T* self)
{
    UINT32 mask = ~(self->lineSize -1);
    UINT32 dict;
    UINT32 dest;
    UINT32 index;
    UINT32 line;
    UINT32 size;

    /*
     * LRU: Least Recently Used
     * lineDict[0] is always LRU dict.
     */
    dict  = self->lineDict[0];
    dest  = MTK_BTST(dict, mask);
    index = MTK_BTST(dict, ~mask);
    line  = self->buffer + self->lineSize * index;
    size  = self->lineSize;

    if (dest < self->destBeg) {
        UINT32 offset = MTK_BTST(self->destBeg, ~mask);
        dest  = self->destBeg;
        size -= offset;
        line += offset;
    }

    if (self->destEnd <= (dest + size)) {
        size = self->destEnd - dest;
    }

    /* printf("FlushLruDict: dest=%08x line=%08x size=%d\n", (INT)dest, (INT)line, (INT)size); */

    WriteDmac((void*)dest, (void*)line, size);

    RotateMruDict(self, 0);
    self->lineUsed--;
    MTK_BSET(self->flag, FLAG_PRELOAD);
}

PRIVATE BOOL CheckDestRange(STORE_BUFFER_T* self, void* dest)
{
    UINT32 mask = ~(self->lineSize - 1);
    UINT32 dest0, beg, end;

    dest0 = MTK_BTST((UINT32)dest, mask);
    beg   = MTK_BTST(self->destBeg, mask);
    end   = MTK_BTST(self->destEnd, mask);

    if ((dest0 < beg) || (end <= dest0)) {
        return FALSE;
    }

    return TRUE;
}

PRIVATE UINT32 WriteLine(STORE_BUFFER_T* self, void* line, const void* dest, const void* src, UINT32 size)
{
    UINT32 mask   = ~(self->lineSize - 1);
    UINT32 offset = MTK_BTST((UINT32)dest, ~mask);
    UINT32 pos    = (UINT32) line + offset;
    UINT32 len    = self->lineSize - offset;
    len = MTK_MIN(len, size);

    memcpy((void*)pos, src, len);

    return len;
}

PRIVATE UINT32 FillLine(STORE_BUFFER_T* self, void* line, const void* dest, INT filler, UINT32 size)
{
    UINT32 mask   = ~(self->lineSize - 1);
    UINT32 offset = MTK_BTST((UINT32)dest, ~mask);
    UINT32 pos    = (UINT32) line + offset;
    UINT32 len    = self->lineSize - offset;
    len = MTK_MIN(len, size);

    memset((void*)pos, filler, len);

    return len;
}

PRIVATE void ShellSort(UINT32* arr, UINT32 num)
{
    UINT32 h;
    UINT32 i, j;

    h = 1;
    while (h < num / 9) {
        h = 3 * h + 1;
    }

    for (; h > 0; h /= 3) {
        for (i = h; i < num; ++i) {
            for (j = i; j >= h; j -= h) {
                if (arr[j - h] > arr[j]) {
                    UINT32 tmp = arr[j - h];
                    arr[j - h] = arr[j];
                    arr[j]     = tmp;
                }
            }
        }
    }
}

PRIVATE void JoinWrite(STORE_BUFFER_T* self)
{
    UINT32 mask = ~(self->lineSize - 1);
    UINT32 dict;
    UINT32 dest;
    UINT32 index;
    UINT32 line;
    UINT32 size;
    UINT32 i;

    LockDmac();

    for (i = 0; i < self->lineUsed; ++i) {
        dict  = self->lineDict[i];
        dest  = MTK_BTST(dict, mask);
        index = MTK_BTST(dict, ~mask);
        line  = self->buffer + self->lineSize * index;
        size  = self->lineSize;

        if (dest < self->destBeg) {
            dest = self->destBeg;
            size = size - (self->destBeg - dest);
            line += MTK_BTST(self->destBeg, ~mask);
        }

        if (self->destEnd <= (dest + size)) {
            size = self->destEnd - dest;
        }

        CacheDmac((void*) dest, (void*) line, size);
    }
    FlushDmac();
    UnlockDmac();
}

既にある自分の Cygwin 環境で gnupack の emacs だけ使ってみたい

うちの環境は 64bit Windows 10 で Cygwin 64bit 版を利用している。

emacsCygwin に入っていたのをターミナルで使っていたが、最近そぞろに GUI 版を使いたくなってきたので gnupack の emacs を入れることにした。

 

ここにその顛末を述べたいと思う。

 

gnupack をインストールする

gnupack Users Guide

gnupackの開発メモ

上記のサイトを参考にインストールする。

emacs だけ欲しいので

パッケージ emacs for gnupack - gnupack - OSDN

にある emacs 24.2 を入れればいいのかもしれないが、 gnupack に入っている emacs のほうが 24.5 とバージョンが新しいようなので欲を掻いて

gnupack_devel-13.06-2015.11.08.exe

を入れることにした。

 

インストール方法は Users Guide に記載あり。ほぼダウンロードして解凍するだけ。

C:\gnupack

にインストールした。

 

emacs の起動

もともと入っている 64bit 版 Cygwinbash を起動し、その中から gnupack Users Guide に書かれた startup_emacs.exe を使って起動を試みる。

 $ /cygdrive/c/gnupack/gnupack_devel-13.06-2015.11.08/startup_emacs.exe

 

起動するにはするが、これだと gnupack 専用の設定で起動してしまう。

 

HOMEの位置も変わってしまうし、いつも使っている .emacs も読んでくれない。

なんか変な感じ。

 

そこで、直接 emacs を起動してみる。

 $ /cygdrive/c/gnupack/gnupack_devel-13.06-2015.11.08/app/cygwin/emacs/bin/emacs.exe 

すると、ウィンドウがポップアップして落ちる。

どうやら 64bit 版 Cygwin からは直接起動できないらしい…。

 

おとなしく gnupack が作り上げた世界で生きていくことも選択肢の一つだが、ここではとりあえず、ふつうの Cygwin 環境で gnupack の提供する emacs だけ使えるようにしてみる。

 

32bit 版 Cygwin を入れる

64bit版 Cygwin からは直接起動できないようなので 32bit Cygwin を入れることにした。(ここで、「Cygwin を入れ直すなら gnupack の構築した世界で生きていけばいいのでは……」という葛藤としばし戦うことになる)

 

Cygwin は ==> こちら

setup-x86.exe (32-bit installation) を使う。 

この記事の執筆時点での最新は 2.5.1。

Cygwinのインストールについては64bit版の別の記事もご参考にどうぞ) 

 

32bit 版 Cygwin から emacs を直接起動してみる

インストールも無事終わり bash を起動して、そこから gnupack の emacs を起動してみる。

すると、下の warning が出て起動しない。 

$ /cygdrive/c/gnupack/gnupack_devel-13.06-2015.11.08/app/cygwin/emacs/bin/emacs
Warning: arch-dependent data dir `/app/cygwin/emacs/libexec/emacs/24.5/i686-pc-cygwin/': No such file or directory
Warning: arch-independent data dir `/app/cygwin/emacs/share/emacs/24.5/etc/': No such file or directory
Warning: Lisp directory `/app/cygwin/emacs/share/emacs/24.5/lisp': No such file or directory
Error: charsets directory not found:
/app/cygwin/emacs/share/emacs/24.5/etc/charsets
Emacs will not function correctly without the character map files.
Please check your installation!

 

/app をマウントする

どうやら gnupack の提供する /app が見えないために emacs が起動しないようなので gnupack についてきた /etc/fstab を参考に /app をマウントする。

 

gnupack の /etc/fstab

# For a description of the file format, see the Users Guide
# http://cygwin.com/cygwin-ug-net/using.html#mount-table
# This is default anyway:
# none /cygdrive cygdrive binary,posix=0,user 0 0
none / cygdrive binary,nouser,noacl,posix=0 0 0
C:/gnupack/gnupack_devel-13.06-2015.11.08/home /home ntfs binary,nouser,noacl,posix=0 0 0
C:/Users/ユーザー名/AppData/Local/Temp/gnupack /tmp ntfs binary,nouser,noacl,posix=0 0 0
C:/gnupack/gnupack_devel-13.06-2015.11.08/app/cygwin/local /usr/local ntfs binary,nouser,noacl,posix=0 0 0
C:/gnupack/gnupack_devel-13.06-2015.11.08 /root ntfs binary,nouser,noacl,posix=0 0 0
C:/gnupack/gnupack_devel-13.06-2015.11.08/app /app ntfs binary,nouser,noacl,posix=0 0 0
C:/Users/ユーザー名/Desktop /desktop ntfs binary,nouser,noacl,posix=0 0 0
C:/Users/ユーザー名/Desktop /top ntfs binary,nouser,noacl,posix=0 0 0

 

 /app は C:/gnupack/gnupack_devel-13.06-2015.11.08/app が本体らしいので、うちの Cygwin の /etc/fstab にも同じ設定を追加する。

# /etc/fstab
#
#    This file is read once by the first process in a Cygwin process tree.
#    To pick up changes, restart all Cygwin processes.  For a description
#    see https://cygwin.com/cygwin-ug-net/using.html#mount-table

# This is default anyway:
none /cygdrive cygdrive binary,posix=0,user 0 0
#none / cygdrive binary,nouser,noacl,posix=0 0 0
#C:/gnupack/gnupack_devel-13.06-2015.11.08/home /home ntfs binary,nouser,noacl,posix=0 0 0
#C:/Users/ユーザー名/AppData/Local/Temp/gnupack /tmp ntfs binary,nouser,noacl,posix=0 0 0
#C:/gnupack/gnupack_devel-13.06-2015.11.08/app/cygwin/local /usr/local ntfs binary,nouser,noacl,posix=0 0 0
#C:/gnupack/gnupack_devel-13.06-2015.11.08 /root ntfs binary,nouser,noacl,posix=0 0 0
C:/gnupack/gnupack_devel-13.06-2015.11.08/app /app ntfs binary,nouser,noacl,posix=0 0 0
#C:/Users/ユーザー名/Desktop /desktop ntfs binary,nouser,noacl,posix=0 0 0
#C:/Users/ユーザー名/Desktop /top ntfs binary,nouser,noacl,posix=0 0 0

 

とりあえず、全部コピペして /app 以外はコメントアウト。 /etc/fstab を保存して

$ mount  /app

を実行してマウント。

 

再度 emacsCygwin から実行してみる

 

$ /app/cygwin/emacs/bin/emacs  &

 

動いた!

 

その他の設定

gnupack の local に入っている諸々にアクセスできるように local もマウントしておいたほうがいいかもしれない。

 

でも /usr/local にマウントされるので、自分で /usr/local にインストールしたものがあるとそれは使えなくなる。

 

そういう向きは、とりあえず gnupack の local/bin に PATH だけ通しておいてもいいかもしれない。

 

.bashrc

  export PATH=/app/cygwin/local/bin:$PATH 

 

私の場合、32bit  Cygwin を入れたばかりで /usr/local には空の bin, etc, lib ディレクトリがあるだけなので mount してみた。

 

/etc/fstab で下の設定のコメントを外し

C:/gnupack/gnupack_devel-13.06-2015.11.08/app/cygwin/local  /usr/local  ntfs binary,nouser,noacl,posix=0 0 0

 /usr/local にマウントする

$ mount  /usr/local

こうすると gnupack に入っている日本語 man も表示出来てありがたい。

$ man 3 printf

 

PRINTF(3)                             Linux Programmer's Manual                            PRINTF(3)

名前
       printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - 指定された書式に
       変換して出力を行う

書式
       #include <stdio.h>

       int printf(const char *format, ...);

...(後略)...

 

やってみたことリスト

今回は、とりあえず起動しただけ。まだ使い込んでいないのでちゃんと動くのか、ちょっと不安だけど、下のようなことは出来た。

  • Cygwinbash から gnupack の emacs を直接起動。OK
  • /app/cygwin/emacs/bin/emacs ~/.bashrc として自分の .bashrc が開く。(gnupack のホームのものではなく)
  • Cygwin の標準的なドライブ指定方式 /cygdrive/c で Cドライブにアクセス。OK。(gnupack では /cygdrive はマウントされない)
  • 日本語入力 OK。ATOK使えた。
  • テキストファイルに utf-8-unix で書いて保存。OK
  • M-x complile 実行。OK。 g++ -g -Wall -std=c++14 -o exe-name src-name.cpp を実行。コンパイルも通り、実行したら動いた。

 

ちょっと前には 64bit Windows では、 64bit Cygwin じゃないとダメなんじゃないかと思っていたけど、気のせいだったかな。それとも Cygwin のほうでなにか対処したのかな。 

 

最後に

今回は、既存の環境に gnupack の emacs だけを追加してみる方法を検討してみたが、その作業のあいだ gnupack が提供してくれる環境を使っていくなかで、これでもいいかな、いやむしろこっちのほうがいいかな、という気持ちに傾きつつある。

どうしよう。