ovs + lacp でのトラブルシューティングメモ
OpenvSwitch + LACP 構成でのメモ
書きかけのメモです
調査の流れ
Bonding 状態確認
ovs-appctl bond/show [bond]
LACP 状態確認
ovs-appctl lacp/show [bond]
Active な NIC を設定
ovs-appctl bond/set-active-slave [bond] [interface]
http://openvswitch.org/pipermail/discuss/2013-October/011651.html
OpenvSwitch バージョン確認
ovs-vsctl --version
チェックする設定項目
http://openvswitch.org/support/dist-docs/ovs-vswitchd.conf.db.5.html
- lacp: active or passive or off
- bond-detect-mode
- bond-hash-basis
- lacp-fallback-ab
関係ある?
network, openvswitch のサービスの起動順
GNU GLOBAL 使用環境設定
GNU GLOBAL をインストール、多言語対応のためのプラグインセットアップの手順
インストール環境
OS: ubuntu server 14.04
GNU GLOBAL のインストールとセットアップ
Ubuntu のパッケージのバージョンは古いので、ソースコードからビルドする。
sudo apt-get install gcc make automake autoconf flex gperf cvs bison libncurses5-dev texinfo ctags libtool
cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/sources/global co global
cd global
sh ./reconf.sh
./configure && make && sudo make install
プラグインによる多言語対応
デフォルトだと対応言語が少ないのでプラグインを入れる。
プラグインには global-pygments-plugin
を使用させていただく。
事前設定
sudo pip install Pygments
sudo apt-get install python-pip libtool
後は、global-pygments-plugin
の README.md の通りにセットアップ
global-pygments-plugin セットアップ
リポジトリのチェックアウトとビルド
git clone https://github.com/yoshizow/global-pygments-plugin
cd global-pygments-plugin
sh ./reconf.sh
./configure && make && sudo make install
.globalrc
は サンプル が用意されているのでそれをベースにする。
ローカルyumサーバを立ててそこを参照して RDO で OpenStack をセットアップ
目標
- インターネットに接続できないサーバに RDO (packstack) を使用して OpenStack を構築できるようにする。
- 上記サーバが接続可能な yum サーバはローカルに構築する
- yum サーバ構築時はインターネットに接続可能とする。
- 各サーバの初期状態は CentOS の 6.5 を minimal インストール (+ zsh, screen, git を yum で入れた状態)
やること
構成
以下みたいな特殊なネットワーク環境
+--------------------------+
| Router |
+--------------------------+
|
|
+--------------------------+
| yum server |
| 172.16.1.1 |
+--------------------------+
|
|
+--------------------------+
| OpenStack |
| 172.16.1.2 |
+--------------------------+
手順
yum サーバー設定
yum.repos.d に リポジトリを追加
公開するパッケージをダウンロードしてくるリポジトリを登録する。 OpenStack のバージョンに応じて以下のサイトから rdo-relase をインストールする。
http://repos.fedorapeople.org/repos/openstack
ブラウザで開いてインストールしたいリリースバージョンをリポジトリとして登録する。
例) havana-7 の場合
yum install http://repos.fedorapeople.org/repos/openstack/openstack-havana/rdo-release-havana-7.noarch.rpm
以下、havana-7 をインストールした場合として進める。
(参考)
rpm -ql rdo-release-havana-7 を実行してインストールされたファイルの確認
/etc/yum.repos.d の下に以下の repo ファイルが追加される:
それぞれの GPG-KEY はそれぞれ以下:
- /etc/pki/rpm-gpg/RPM-GPG-KEY-RDO-Havana
- /etc/pki/rpm-gpg/RPM-GPG-KEY-foreman
- /etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs
これらのリポジトリから rpm をダウンロードしてローカルに公開すれば良い。
http サーバを準備
http で公開するため、httpd
を入れる。
(http サーバなら何でも良いが簡単なので)
yum install httpd
chkconfig httpd on
service httpd start
apache の設定は省略。 その他、selinux やら iptables やら、hosts.allow やらセキュリティポリシに合わせて設定。 ここでは、ローカルの実験用環境なのでノーガード設定。
chkconfig iptables off
service iptables stop
setenforce 0
sed -i -e 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
yum リポジトリをローカルに sync して公開
yum リポジトリのメタデータを作成するための createrepo
と リポジトリからダウンロードするための yum-utils
を入れる。
yum install createrepo yum-utils
rdo 関係リポジトリ
追加したリポジトリの rpm をローカルに sync する。 コマンドは以下 (sync には時間がかかるので注意) そのまま公開できるように /var/www/html 以下で作業する。
cd /var/www/html
reposync -r openstack-havana -n -t /var/cache/yum
reposync -r puppetlabs-products -n -t /var/cache/yum
reposync -r puppetlabs-deps -n -t /var/cache/yum
createrepo ./openstack-havana
createrepo ./puppetlabs-products
createrepo ./puppetlabs-deps
参考までにファイルサイズ
du -hs ./openstack-havana/
438M ./openstack-havana/
du -hs ./puppetlabs-products/
101M ./puppetlabs-products/
du -hs ./puppetlabs-deps/
61M ./puppetlabs-deps/
(補足情報)
reposync
はリポジトリで公開されている rpm をダウンロードする。- 保存先は
<カレントディレクトリ>/<リポジトリ名>/
の下 -n
をつけると最新のものだけをダウンロードする。 そのリリースバージョンの古いものも欲しかったら指定しない。- 他のオプションは
man reposync
参照
- 保存先は
createrepo
は指定ディレクトリ以下を yum リポジトリとするための metadata を作成する
CentOS の基本リポジトリ
base
, extras
, updates
のパッケージが必要。
reposync
で持ってくる方法と配布されている DVD メディアを使用する方法がある。
reposync する場合
reposync して最新のものを持ってくる。 ただ、ファイルサイズが大きいので回線速度にもよるが結構な時間がかかる。
cd /var/www/html
reposync -r base -n -t /var/cache/yum
reposync -r extras -n -t /var/cache/yum
reposync -r updates -n -t /var/cache/yum
createrepo ./base
createrepo ./extras
createrepo ./updates
参考までにファイルサイズ
du -hs ./base/
5.2G ./base/
du -hs ./extras/
9.2M ./extras/
du -hs ./updates/
1.1G ./updates/
media を使用する場合
配布されている DVD のイメージがあればそれを使用した方が早い。
以下手順。
まず、どうにかしてディスクイメージをホストに持っていく VMware 環境の場合はゲストの仮想ドライブを使用するなり、 ISO の場合はそのままホストにコピーして使用するなり。
マウントして中身コピー
mount /dev/cdrom /mnt
cp -rf /mnt/Packages/ /var/www/html/media
ISO を直接持っていった場合は mount -o loop
とか、
DVD2 に入っているものも使うので、DVD1, DVD2 それぞれで上記を実施。
コピーが終わったら createrepo
で metadata を生成する。
パッケージ数が多いので時間がかかる、、、
cd /var/www/html/
createrepo ./media
EPEL
epel の一部パッケージも使用するのでその準備。 epel のリポジトリ登録 (参考: https://fedoraproject.org/wiki/EPEL)
yum install http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/i386/epel-release-6-8.noarch.rpm
reposync しても良いが、サイズが大きくダウンロードするにも時間がかかるので (大体 10 GB ぐらい) 必要なものだけをダウンロードしてリポジトリ化する。
rpm のダウンロードには yum の downloadonly plugin を使用する。 これを入れて yum install に --downloadonly オプションを指定するとインストールはせずに /var/cache/yum にダウンロードだけしてくれる。
openstack のコンポーネントのパッケージ指定だけして、パッケージのリストアップは yum にまかせる。
yum install --downloadonly openstack-nova openstack-nova-compute openstack-glance openstack-neutron openstack-swift openstack-keystone openstack-cinder openstack-ceilometer-common openstack-heat python-django-compressor openstack-swift-plugin-swift3 mongodb-server openstack-ceilometer-api
yum install --downloadonly nagios-plugins-nrpe nagios-plugins-ping nagios nrpe
上記で大体の構成で必要なものは揃っているはず、、、足りないものがあったら適宜追加。
cd /var/www/html/
mkdir epel
cp /var/cache/yum/x86_64/6/epel/packages/*.rpm ./epel/
OpenStack 側
yum リポジトリ設定
yum server と同様に rdo-realse をインストール。 ただし、今度は先ほど立てた yum サーバから
yum install http://172.16.1.1/openstack-havana/rdo-release-havana-7.noarch.rpm
openstack-havana と puppetlabs の URL を書き換えてローカルに向ける。
sed -i -e 's/repos.fedorapeople.org\/repos\/openstack\/openstack-havana\/epel-6/172.16.1.1\/openstack-havana/' /etc/yum.repos.d/rdo-release.repo
sed -i -e 's/yum.puppetlabs.com\/el\/6\/products\/\$basearch/172.16.1.1\/puppetlabs-products/' /etc/yum.repos.d/puppetlabs.repo
sed -i -e 's/yum.puppetlabs.com\/el\/6\/dependencies\/\$basearch/172.16.1.1\/puppetlabs-deps/' /etc/yum.repos.d/puppetlabs.repo
foreman.repo は使用しないので無効化しておく
sed -i -e 's/enabled=1/enabled=0/' /etc/yum.repos.d/foreman.repo
yum サーバ上のリポジトリを記載する。 ローカルだし面倒なので GPG-KEY はなし。 epel のリポジトリ名は [epel] にすると packstack に enabled=0 されてしまうので適当な名前を付けること
vi /etc/yum.repos.d/local.repo
media か base, extras, updates かはどの手順で作成したかによって enabled を切り替える。
[media]
name=CentOS Media
baseurl=http://172.16.1.1/media
enabled=0
gpgcheck=0
[base]
name=CentOS Media
baseurl=http://172.16.1.1/base
enabled=1
gpgcheck=0
[extras]
name=CentOS Media
baseurl=http://172.16.1.1/extras
enabled=1
gpgcheck=0
[updates]
name=CentOS Media
baseurl=http://172.16.1.1/updates
enabled=1
gpgcheck=0
[epel-part]
name=Part of EPEL
baseurl=http://172.16.1.1/epel
enabled=1
gpgcheck=0
NameServer 設定
nameserver が設定されていないと packstack が実行できないので 設定する、今回は yum サーバと同じ 172.16.1.1 を nameserver とする。
NameServer 側
dnsmasq を入れて、172.16.1.2 の名前を応答するようにしておく。 (172.16.1.2 のホスト名は rdo-havana)
yum install dnsmasq
echo "listen-address=127.0.0.1,172.16.1.1" >> /etc/dnsmasq.conf
echo "172.16.1.2 rdo-havana" >> /etc/hosts
OpenStack サーバ側
name server のアドレスとして 172.16.1.1 を登録
echo "nameserver 172.16.1.1" >> /etc/resolv.conf
packstack によるセットアップ中は自身の IP アドレスの名前解決を何度も行うので /etc/hosts に書いておく。
echo "172.16.1.2 rdo-havana rdo-havana.local" >> /etc/hosts
もちろん DNS サーバ側に問い合わて解決させても良いけど、 自己解決させた方が無駄に通信を行わない。
packstack 実行
OpenStack をインストールするホストで packstack を実行して、OpenStack をセットアップする。
packstack では answer ファイルを用意することで構成を変更することができるが、 ここでは allinone ですべてつっこむ。 (packstack の使い方についてはここでは割愛。公式のドキュメントがわかりやすいので見てください)
そのまま実行すると、RDO が epel リポジトリを yum.repos.d に追加して 接続しようとするためこけるので、--use-epel オプションに n を指定する。
packstack --allinone --use-epel=n
性能によるが、大体 30 分ぐらいでセットアップが終わる。
課題
CirrOS がダウンロードできない。
RDO では本来は最初から使えるイメージとして CirrOS が用意されるはずだが 途中でイメージのダウンロードできないため、CirrOS が無い状態になってしまう。
やらないといけないこと - download.cirros-cloud.net. を名前解決させて 172.16.1.1 に向ける - そこから CirrOS をダウンロードさせる
http プロキシ環境内で OpenDaylight とりあえず動かしたメモ
OpenDaylight をプロキシ越しでしかインターネッツアクセスできない環境内でセットアップしたときのメモ
とりあえず Ubuntu server 12.10 に OpenDaylight 入れて画面確認したところまで
2013/4/14 時点のソースコードで実施
下準備
多分以下の 3 つが入っていれば OK. apt の proxy 設定を /etc/apt/apt.conf で行なっておくこと。
git
sudo apt-get install git
java
sudo apt-get install openjdk-7-jdk
maven3
sudo apt-get install maven wget http://ftp.br.debian.org/debian/pool/main/m/maven/maven_3.0.4-3_all.deb dpkg -i maven_3.0.4-3_all.deb
ビルド
ソースコードをチェックアウト
git clone http://git.opendaylight.org/gerrit/p/controller.git
maven のプロキシ設定
ビルド中に依存解決のため http アクセスしまくるのでプロキシ設定しておく
vi ~/.m2/settings.xml <settings> <proxies> <proxy> <active>true</active> <protocol>http</protocol> <host>プロキシホスト</host> <port>ポート番号</port> <username>ユーザ名</username> <password>パスワード</password> <nonProxyHosts>プロキシ使わないドメイン</nonProxyHosts> </proxy> </proxies> </settings>
ビルド実行
デフォ状態だと OutOfMemory でこけたのでメモリ割り当てを増やしておく
export MAVEN_OPTS='-Xmx1024m -XX:MaxPermSize=256m'
pom.xml があるディレクトリに移動してテスト、インストール
cd controller/opendaylight/distribution/opendaylight/ mvn test
問題なければ
mvn install
実行
cd target/<ビルド名>/opendaylight
そのまま実行すると http 越しの beans を読みにいってエラーが出るのでここでも http の Proxy 設定
vi run.sh $JAVA_HOME/bin/java $@ \ -Djava.io.tmpdir=${basedir}/work/tmp \ -Dosgi.install.area=${basedir} \ -Dosgi.configuration.area=${basedir}/configuration \ -Dosgi.frameworkClassPath=${FWCLASSPATH} \ -Dosgi.framework=file:${basedir}/lib/org.eclipse.osgi-3.8.1.v20120830-144521.jar \ + -Dhttp.proxyHost="プロキシホスト名" \ + -Dhttp.proxyPort="ポート番号" \ + -Dhttp.proxyUser="ユーザ名" \ + -Dhttp.proxyPassword="パスワード" \ -classpath ${CLASSPATH} \ org.eclipse.equinox.launcher.Main \ -console \ -consoleLog
環境変数 JAVA_HOME を設定してから run.sh を実行
./run.sh
httpで 8080 ポートにアクセスすれば画面が見えるはず
Vim で現在カーソルがある行と同じインデントを強調表示
最近ちょっと Vim で python を読む機会があったのだけど、ぱっと見てインデントが同じ行がどこまで分からず読み辛かった。
そんなわけで、現在カーソルがある行と同じ(もしくはそれ以上の)インデントレベルのところを強調表示する方法を模索したのでそのメモ
方法1: vim-indent-guides を使う
インデントを強調表示する、で検索すると出てきたのがこれ。
パッと使った感じ、以下の機能があった
- 等間隔で列を強調表示可能
- 色は自由に指定可能
多分もっと高機能っぽいけど、今回はこんなにおおげさな機能はいらなかった(というかデフォルトのままだと情報量が多すぎる。カスタマイズするのは面倒だった)のでパス
方法2: 適宜 highlight パターンを作る
今回とったのはこっち。
現在カーソルがある行の文字列を取得して、highlight 対象とするパターンを返却する簡単な関数を作った。
以下その関数
function! s:indent_pattern() let l:line = getline('.') let l:indent = matchstr(l:line, '^\zs\s\+\ze\S') let l:len = len(l:indent) - 1 if l:len > 0 return '^\s\{'. l:len . '}\zs\s\ze' else return '^\zs\s\ze' endif endfunction
# これだとスペースとタブが入り混じってると変な highlight になるけど気にしない。そんなコード書く方が悪い。
この関数から取得したパターンを matchadd で適当な highlight に追加してやればやりたいことができるはず。
matchadd とか matchdel する仕組みについては、ここ何回か同じような仕組みでほげほげしてきたので、ある程度汎用的に使えるようにした。
以下そのコード
" defined highlight sources let g:auto_highlights = {} " control enable/disable auto highlighting let g:enable_auto_highlight = 1 " disable auto highlight when filetype in below let g:auto_highlight_disable_file_type = ['unite', 'tmp'] function! s:compare_source(i1, i2) return a:i1.priority == a:i2.priority ? 0 : a:i1.priority > a:i2.priority ? 1 : -1 endfunction function! s:init_window_auto_highlight() let l:info = {} for highlight_kind in keys(g:auto_highlights) let l:info[highlight_kind] ={ \ 'current_match_pattern' : '', \ 'current_match_id' : -1, \} endfor return l:info endfunction " function for add highlight source function! s:define_auto_highlight_source(src) if !has_key(g:auto_highlights, a:src.highlight) let g:auto_highlights[a:src.highlight] = { \ 'sources' : [], \} endif call add(g:auto_highlights[a:src.highlight].sources, a:src) call sort(g:auto_highlights[a:src.highlight].sources, 's:compare_source') endfunction " main function! s:start_highlight() if !get(g:, "enable_auto_highlight", 0) || index(get(g:, 'auto_highlight_disable_file_type', []), &filetype) >= 0 return endif if !exists('w:auto_highlight_info') let w:auto_highlight_info = s:init_window_auto_highlight() endif for [item, value] in items(g:auto_highlights) for src in value.sources let l:pattern = src.pattern() if !empty(l:pattern) let l:target = w:auto_highlight_info[item] if l:target['current_match_pattern'] != l:pattern call s:ClearHighlight(item) let l:target['current_match_pattern'] = l:pattern let l:target['current_match_id'] = matchadd(item, l:pattern, src.priority) endif break endif endfor endfor endfunction " clear before highlight function! s:ClearHighlight(kind) if exists('w:auto_highlight_info') if w:auto_highlight_info[a:kind].current_match_id >= 0 call matchdelete(w:auto_highlight_info[a:kind].current_match_id) let w:auto_highlight_info[a:kind].current_match_id = -1 let w:auto_highlight_info[a:kind].current_match_pattern = '' endif endif endfunction " toggle enable/disable auto highlight function! s:toggle_auto_highlight() let g:enable_auto_highlight = !get(g:, "enable_auto_highlight", 0) call s:CheckEnableHighlightCurrentWord() endfunction function! s:CheckEnableHighlightCurrentWord() if !g:enable_auto_highlight for kind in keys(g:auto_highlights) call s:ClearHighlight(kind) endfor endif endfunction command! -bar ToggleCurrentHighlight call s:toggle_auto_highlight() command! -bar CurrentHighlight call s:start_highlight()
後、適当な autocmd に CurrentHighlight を実行するように設定してやる。
で、これまで作成した highlight を登録
" current word highlight let s:cword_highlight = { \ 'name': 'current_word', \ 'highlight': 'CurrentWord', \ 'priority': 10, \} function! s:EscapeText( text ) return substitute( escape(a:text, '\' . '^$.*[~'), "\n", '\\n', 'ge' ) endfunction function! s:cword_highlight.pattern() let l:cwd = expand('<cword>') if empty(l:cwd) return '' else let l:regexp = s:EscapeText(l:cwd) return l:cwd =~# '^\k\+$' ? '\<' . l:regexp . '\>' : l:regexp endif endfunction call s:define_auto_highlight_source(s:cword_highlight) " matchit highlight let s:matchit_highlight = { \ 'name': 'matchit', \ 'highlight': 'CurrentWord', \ 'priority': 9, \} function! s:InitMatchit() if !exists('b:match_words') return endif let l:mw = filter(split(b:match_words, ',\|:'), 'v:val !~ "^[(){}[\\]]$"') let b:reserved_regexp = join(l:mw, '\|') let mwre = '\%(' . b:reserved_regexp . '\)' let b:mwre = substitute(mwre, "'", "''", 'g') endfunction function! s:matchit_highlight.pattern() if !exists('b:match_words') return '' endif if !exists('b:reserved_regexp') call s:InitMatchit() endif if expand("<cword>") !~ b:reserved_regexp || empty(b:reserved_regexp) return '' endif let lcs = [] let wsv = winsaveview() while 1 exe 'normal %' let lc = {'line': line('.'), 'col': col('.')} if len(lcs) > 0 && (lcs[0] == lc || lcs[-1] == lc) break endif call add(lcs, lc) endwhile call winrestview(wsv) call map(lcs, '"\\%" . v:val.line . "l\\%" . v:val.col . "c"') let lcre = join(lcs, '\|') " final \& part of the regexp is a hack to improve html return '.*\%(' . lcre . '\).*\&' . b:mwre "return '.*\%(' . lcre . '\).*\&' . b:mwre . '\&\% (<\_[^>]\+>\|.*\)' endfunction call s:define_auto_highlight_source(s:matchit_highlight) " indent highlight let s:indent_highlight = { \ 'name': 'indent', \ 'highlight': 'Indent', \ 'priority': 10, \} function! s:indent_highlight.pattern() let l:line = getline('.') let l:indent = matchstr(l:line, '^\zs\s\+\ze\S') let l:len = len(l:indent) - 1 if l:len > 0 return '^\s\{'. l:len . '}\zs\s\ze' else return '^\zs\s\ze' endif endfunction call s:define_auto_highlight_source(s:indent_highlight)
作っておいて何だけど多分これ以上 source 増やさない。あんまり情報量増えても害なので…
以下あったら嬉しいかもしれない機能
- 変数の上にカーソルがあるとき、その変数の定義部分 or 代入部分だけ色を変える
Vim で if endif とか対応するキーワードを強調表示する
昨日の続き
はじめに
カーソルが if とか対応するものが存在するキーワード上にあるとき、endif とか対応するキーワードを強調表示させる。この機能も多分大体の IDE にはあると思う。
これも Vim でコード読むときあったら便利な気がしたので調べた。
これを実現するための要素
- カーソルの下の単語が if とか for とか対応するワードが存在するものかどうかの判別
- 対応するキーワードの取得 (できればネストの考慮)
他、前回の内容
コード
実は "matchit highlight" でググれば同じようなことをしている人が見つかった。
(リンクはっていいか不明なので省略、ググってください)
それを参考にしつつ、記述したのが以下のコード
function! s:GetMatchitPattern(cwd) if !exists('b:match_words') return '' endif if !exists('b:mw') call s:InitMatchit() endif for pat in b:mw if a:cwd =~# pat let l:cmw = pat break endif endfor if !exists("l:cmw") return '' endif let lcs = [] let wsv = winsaveview() while 1 exe 'normal %' let lc = {'line': line('.'), 'col': col('.')} if len(lcs) > 0 if (lc.line == lcs[0].line && lc.col == lcs[0].col) || (lc.line == lcs[-1].line && lc.col == lcs[-1].col) break endif endif call add(lcs, lc) endwhile call winrestview(wsv) call map(lcs, '"\\%" . v:val.line . "l\\%" . v:val.col . "c"') let lcre = join(lcs, '\|') return '.*\%(' . lcre . '\).*\&' . b:mwre endfunction function! s:InitMatchit() if !exists('b:match_words') return endif let b:mw = split(b:match_words, ',\|:') let l:mw = filter(b:mw, 'v:val !~ "^[(){}[\\]]$"') let mwre = '\%(' . join(l:mw, '\|') . '\)' let b:mwre = substitute(mwre, "'", "''", 'g') endfunction
(ほとんど参考元と同じ)
matchit.vim を有効にしていないと動作しません
上記の s:GetMatchitPattern の戻り値を前回同様 matchadd で指定してやれば、if, else, endif などが強調表示される。
内容メモ
ポイントは以下
- b:match_words
- マッチング用の正規表現に行番号と列番号を使用
- winsaveview() と exe 'normal %', winrestview()
b:match_words
b:match_words は matchit.vim プラグインが ( や { 以外の言語特有の対応パターンを認識するのに使用している変数。
file type のプラグインなどで、 <開始パターン>[:<中間パターン>]:<終了パターン>[,他パターン...] の形式で定義されている。
例) filetype=vim の場合(一部抜粋)
\<fu\%[nction]\>:\<retu\%[rn]\>:\<endf\%[unction]\>,\<\(wh\%[ile]\|for\)\>:\<brea\%[k]\>:\<con\%[tinue]\>:\<end\(w\%[hile]\|fo\%[r]\)\>
このパターンを使用して、現在のカーソル下の単語が特殊なキーワードかどうか判別できる
その場合は、split() を使用して、',' と '|' で分割してやればよい
マッチング用の正規表現に行番号と列番号を使用
例えば、"\%100l" のように指定するとそのファイルの 100 行目がマッチング対象となる。
さらに、"\%100l\%2c" と指定すれば、ファイルの 100 行目の 2 文字目がマッチング対象となる。
後は、その文字の後ろに b:match_words から取り出した単語をマッチング対象として加えれば良い。
winsaveview() と exe 'normal %', winrestview()
簡単に説明すると、
1. winsaveview() で現在の画面の状態を保存
2. exe 'normal %' で '%' を押したのと同じ状態にする (この後、現在の行番号と列番号を取得)
3. winrestview() で最初に保存した画面の状態を復元
関連する help
- b:match_words
- len()
- add()
- exists()
- line()
- col()
- map()
- filter()
- split()
- join()
- execute
- winsaveview()
- winrestview()
Vim で現在の単語を強調表示する
はじめに
IDE なんかでよくある現在の単語が強調表示されるあの機能が vim でも欲しくなった。
ググっても似たようなことしてる人も見つからないし、簡単な内容なので、vim script の勉強がてら書いてみる
以下ができれば実現できるはず
- カーソル下の単語取得
- highlight の設定方法
- 適当なトリガー設定
コード
もったいぶるほどでもないので書いてしまうと以下のようになった
highlight CurrentWord term=NONE ctermbg=DarkMagenta ctermfg=NONE function! s:EscapeText( text ) return substitute( escape(a:text, '\' . '^$.*[~'), "\n", '\\n', 'ge' ) endfunction function! s:GetCurrentWord() let l:cword = expand('<cword>') if !empty(l:cword) let l:regexp = s:EscapeText(l:cword) if l:cword =~# '^\k\+$' let l:regexp = '\<' . l:regexp . '\>' endif return l:regexp else return '' endif endfunction function! s:HighlightCurrentWord() let l:word = s:GetCurrentWord() if !empty(l:word) if exists("w:current_match") call matchdelete(w:current_match) endif let w:current_match = matchadd('CurrentWord', l:word, 0) endif endfunction augroup cwh autocmd! autocmd CursorMoved,CursorMovedI * call s:HighlightCurrentWord() augroup END
上の内容を vimrc に記述すればスコープとかは気にしなければ大体思った機能になる
内容メモ
大雑把な内容は
1. カーソル下の単語取得
2. 取得した単語をエスケープしたりマッチングする文字列に変換
3. すでにマッチングしてるものがある場合は highlight 対象から削除
4. highlight にマッチング対象文字列追加
autocmd のカーソル移動系にこの関数を追加
課題
- カーソル移動系から呼ぶと無駄に重い
- スコープを考慮できたらいいかもしれない
- if とか while とか matchit 系は対応するキーワードが強調された方が多分便利