2008/01/31


Googleが提供している開発用tagツールGoogle GTags(gtags)をWindowsで動かす手順です。
以下、パッチを上げてますが、接続タイムアウトのalarmを無効化しています。必要だと思われる人は、SIGALRMを別の方法で実装してください。
まず、サイトからsvnで最新ソースを取得します。
C:\TEMP> svn checkout http://google-gtags.googlecode.com/svn/trunk/ google-gtags 次に、以下のパッチを当てます。
Index: regexp.h
===================================================================
--- regexp.h    (revision 57)
+++ regexp.h    (working copy)
@@ -4,7 +4,9 @@
 #ifndef TOOLS_TAGS_REGEXP_H__
 #define TOOLS_TAGS_REGEXP_H__
 
+extern "C" {
 #include <regex.h>
+}
 #include "tagsutil.h"
 
 class RegExp {
Index: configure
===================================================================
--- configure   (revision 57)
+++ configure   (working copy)
@@ -10,7 +10,7 @@
 if [ ! -e "scons/scons.py" ]; then
     pushd scons > /dev/null
     echo "Unpacking scons..."
-    tar xzvf scons-local.tar.gz > /dev/null
+    gzip -dc scons-local.tar.gz | tar xv > /dev/null
     if [[ "$?" == 0 ]]; then
    echo "Done"
     else
Index: gtags.cc
===================================================================
--- gtags.cc    (revision 57)
+++ gtags.cc    (working copy)
@@ -49,6 +49,10 @@
 #include "tagsoptionparser.h"
 #include "tagsrequesthandler.h"
 
+#ifdef WIN32
+# include <winsock2.h>
+#endif
+
 DEFINE_STRING(tags_file, "", "The file containing the tags information.");
 
 
@@ -78,6 +82,11 @@
     return -1;
   }
 
+#ifdef _WIN32
+  WSAData wsadata;
+  WSAStartup(MAKEWORD(2,0), &wsadata);
+#endif
+
   logger = new StdErrLogger();
 
   tags_request_handler = new TagsRequestHandler(GET_FLAG(tags_file),
@@ -90,4 +99,9 @@
 
   delete tags_request_handler;
   delete logger;
+
+
+#ifdef _WIN32
+  WSACleanup();
+#endif
 }
Index: gtags.py
===================================================================
--- gtags.py    (revision 57)
+++ gtags.py    (working copy)
@@ -175,11 +175,11 @@
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      address = socket.getaddrinfo(host, port, socket.AF_INET,
                                socket.SOCK_STREAM)
-     signal.signal(signal.SIGALRM, alarm_handler)
-     signal.alarm(CONNECT_TIMEOUT)
+     #signal.signal(signal.SIGALRM, alarm_handler)
+     #signal.alarm(CONNECT_TIMEOUT)
      s.connect(address[0][4])
-     signal.alarm(0)
-     signal.alarm(DATA_TIMEOUT)
+     #signal.alarm(0)
+     #signal.alarm(DATA_TIMEOUT)
 
      # need \r\n to match telnet protocol
      s.sendall(command + '\r\n')
@@ -191,7 +191,7 @@
      while data:
        buf.write(data)
        data = s.recv(1024)
-     signal.alarm(0)
+     #signal.alarm(0)
      return buf.getvalue()
 
 # Instance of connection_manager that forwards client requests to gtags server
Index: tags_logger.h
===================================================================
--- tags_logger.h   (revision 57)
+++ tags_logger.h   (working copy)
@@ -67,6 +67,7 @@
   }
 };
 
+#undef ERROR
 const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3, NUM_SEVERITIES = 4;
 
 // uncomment out the standard google logger
Index: socket_server.cc
===================================================================
--- socket_server.cc    (revision 57)
+++ socket_server.cc    (working copy)
@@ -18,10 +18,14 @@
 
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
+#ifdef WIN32
+# include <winsock2.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <unistd.h>
+#endif
 #include <string>
 
 #include "tagsprofiler.h"
@@ -29,6 +33,12 @@
 #include "tagsrequesthandler.h"
 #include "socket_server.h"
 
+#ifdef WIN32
+typedef int socklen_t;
+#define write(x, y, z) send(x, y, z, 0)
+#define close(x) closesocket(x)
+#endif
+
 extern GtagsLogger* logger;
 
 DEFINE_INT32(tags_port, 2222, "port to tags server");
次にgoogle-gtagsのソースルートにregex for win32を解凍します。これで、gnu_regex_distというフォルダが出来ます。
zsh for win32等をお持ちの方ならば、そのまま sh configure
お持ちでない方でもconfigureの中身を見ると大体検討が付きます。
Makefile.w32は以下の通り。mingw32-makeでビルドします。
all: gtags.exe

gtags.exe : filename.cc gtags.cc sexpression.cc strutil.cc symboltable.cc tagsoptionparser.cc tagsprofiler.cc tagsrequesthandler.cc tagstable.cc socket_server.cc gnu_regex_dist/regex.c
    gcc -DHAVE_STRING_H -c -I. gnu_regex_dist/regex.c
    gcc -I. -Ignu_regex_dist -o gtags.exe filename.cc gtags.cc sexpression.cc strutil.cc symboltable.cc tagsoptionparser.cc tagsprofiler.cc tagsrequesthandler.cc tagstable.cc socket_server.cc regex.o -lstdc++ -lws2_32
あとはspiritlooseのはてなダイアリー - [Vim]Google Tags(GTags)を試してみた(with Vim)を参考に lang_call_to_server = {
  "c++" : { "definition" : [("localhost", 2222)],
            "callgraph" : [] },
  "java" : { "definition" : [],
             "callgraph" : [] },
  "python" : { "definition" : [],
               "callgraph" : [] } }
等と設定して、vimrcに exec "set runtimepath+=".escape(globpath(&runtimepath, 'gtags'), ' ')
nmap <C-]> :call Gtag(expand('<cword>'))<CR>
を追加します。
これで設定はOKです。次に以下の手順でソースツリーでtagsファイルを生成します。
python c:/temp/google-gtags/gentags.py --etags=c:/emacs/bin/etags.exe --rtags=c:/temp/google-gtags/rtags.py --etags_to_tags=c:/temp/google-gtags/etags_to_tags.py ここではetagsとしてemacsに含まれるバイナリを使用しましたが、ctags.exeをetags.exeにリネームしても同様に使えます。
これで「cpp.tags.gz」というファイルが生成されますので、あとはサーバを起動します。
c:/temp/gtags.exe --tags_file ./cpp.tags.gz --tags_port 2222 --gunzip 起動したらvim(gvim)を起動して、タグジャンプしたい部分でC-]します。
spiritlooseさんの言うように確かに速いですね。共同開発等では便利かもしれませんね。

オフトピですが、このライブラリに含まれるSconsというビルドツールについて今度調べてみようかと思います。
Posted at by




vim_html 普段vimを使っていらっしゃる方は、ソースコードや/etcにある設定ファイル等をブログに書きたいと思う事が多いかと思います。
私のブログでもほぼ7割方ソースコードが含まれるブログ記事となっています。

ソースコードをブログにアップする際、やはりテキストエディタの様にシンタックスに色が付いた常態だと分かりやすいですよね。
世の中には色んな方法があるようです。

ただ、私としてはやはり静的ファイルでHTMLを出力したいし、なるべく多くのフォーマットで、かつマルチバイトに対応していてほしい。
私は普段テキストエディタとしてvimを使っていますが、vimのソースコードハイライト機能はタダモノではなく、かつ対応しているファイルフォーマットの数も :echo len(split(globpath(&rtp, "syntax/*.vim"),"\n"))
とするだけでも500個以上のファイルフォーマットに対応している事が分かります。
さらにvimのオフィシャルサイトに行けば世の中に存在するプログラミング言語のほぼ全てのsyntaxファイルが揃うでしょう。
vimにも、HTML出力の機能が無いわけではありません。「tohtml.vim」を使えば現在ハイライトされているバッファの中身をHTMLファイルにしてくれる機能があります。
#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("Hello, World\n");
    return 0;
}
こんなファイルであれば :TOHtml
とする事で <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>C:/temp/helloworld.c.html</title>
<meta name="Generator" content="Vim/7.1">
</head>
<body bgcolor="#000000" text="#c0c0c0"><font face="monospace">
<font color="#ff6060">#include </font><font color="#ff40ff">&lt;stdio.h&gt;</font><br>
<br>
<font color="#00ff00">int</font>&nbsp;main(<font color="#00ff00">int</font>&nbsp;argc, <font color="#00ff00">char</font>* argv[]) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;printf(<font color="#ff40ff">&quot;Hello, World</font><font color="#008080">\n</font><font color="#ff40ff">&quot;</font>);<br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#00ffff">return</font>&nbsp;<font color="#ff40ff">0</font>;<br>
}<br>
</font></body>
</html>
こんなHTMLを出力してくれます。
ただ...<font>はいただけませんね。

最近のHTMLでは御法度です。HTML Validatorも許しません。HTMLに直接色を埋め込むなんて最近ではタブー化しつつあります。(このサイトには沢山ありますが...)

今回は、「tohtml.vim」から実行される「2html.vim」を使用してブログに最適なHTMLを出力出来るコツを説明して行きます。
「2html.vim」は基本動作を変えられるように複数のオプションを持っています。以下そのオプションについて説明します。

use_xhtml

出力するHTMLをXHTMLに強制します。たとえば<br>は<br />と出力されます。
また<DOCTYPE>も合わせて変更されます。

html_number_lines

HTMLを出力する際に行番号を出力してくれます。ただし同一要素内に出力されますのでマウスで選択すると行番号まで選択されてしまいます。

html_font

HTMLのフォントを強制出来ます。通常はmonospaceが使われますが、これよりも優先したいフォントがある場合に使用します。

html_use_css

コードのシンタックスを<font>ではなく<span>で出力します。
class属性は上記「Comment」や「Statement」といった識別が使用されます。

html_use_encoding

metaタグでcharset指定できます。但し現状の「2html.vim」にはencodingが「cp932」の場合の処理がありませんので、以下のパッチを「2html.vim」に当てる必要があります。
*** 2html.vim   Fri Aug 03 13:23:20 2007
--- 2html.vim.org   Tue Jul 31 09:48:00 2007
***************
*** 162,168 ****
      let s:html_encoding = 'iso-8859-1'
    elseif s:vim_encoding =~ "^cp12"
      let s:html_encoding = substitute(s:vim_encoding, 'cp', 'windows-', '')
!   elseif s:vim_encoding == 'sjis' || s:vim_encoding == 'cp932'
      let s:html_encoding = 'Shift_JIS'
    elseif s:vim_encoding == 'big5'
      let s:html_encoding = "Big5"
--- 162,168 ----
      let s:html_encoding = 'iso-8859-1'
    elseif s:vim_encoding =~ "^cp12"
      let s:html_encoding = substitute(s:vim_encoding, 'cp', 'windows-', '')
!   elseif s:vim_encoding == 'sjis'
      let s:html_encoding = 'Shift_JIS'
    elseif s:vim_encoding == 'big5'
      let s:html_encoding = "Big5"
これでWindowsを使っていらっしゃる人でも「charset=Shift_JIS」と出力されます。

html_no_pre

<pre>を使わずHTML出力する際に使用します。最近はRSSで全文配信する風潮もあるみたいで、その際に<![CDATA[...]]>使いたくない人には有用かもしれません。

html_start_line

ソースからHTMLを生成する際の開始行番号を指定します。

html_end_ilne

ソースからHTMLを生成する際の終了行番号を指定します。

html_ignore_folding

ソースコードがfoldingされていても内部をHTML出力するように設定します。
設定せずにfoldingされているソースをHTML出力すると以下のようなHTMLが出力されます。
#include <stdio.h>

int main(int argc, char* argv[]) {
+---  2 行:printf("Hello, World\n");
}

html_whole_filler

foldingモード時に、追加された行を意味する行「... inserted lines」を表示したく無い場合に設定します。

以上が「2html.vim」で使用できるオプションです。
通常は何も設定されていませんが、以下ではブログ等に貼り付ける際の私なりのコツを示します。
  • スタイルシートを定義する
  • CSSファイルやHTMLファイルの<style>部に以下のコードを追加しておきます。
    .code {
     border-bottom    : 1px solid #777777;
     border-left      : 5px solid #777777;
     border-right     : 1px solid #777777;
     border-top       : 1px solid #777777;
     background       : #555555;
     color            : #ffffff;
     overflow-x       : auto;
     white-space      : nowrap;
     font-family      : monospace;
    }

    /* source code */
    .code>.Comment {
     color: #aaaaaa;
    }
    .code>.Constant,
    .code>.String,
    .code>.Character,
    .code>.Number,
    .code>.Boolean,
    .code>.Float {
      color: #aa7777;
    }
    .code>.Identifier,
    .code>.Function {
     color: #77aa77;
    }
    .code>.Statement,
    .code>.Conditional,
    .code>.Repeat,
    .code>.Label,
    .code>.Operator,
    .code>.Keyword,
    .code>.Exception {
     color: #77aaaa;
    }
    .code>.PreProc,
    .code>.Include,
    .code>.Define,
    .code>.Macro,
    .code>.PreCondit {
     color: #aaffff;
    }
    .code>.Type,
    .code>.StorageClass,
    .code>.Structure,
    .code>.Typedef {
     color: #aaaa55;
    }
    .code>.Special,
    .code>.SpecialChar,
    .code>.Tag,
    .code>.Delimiter,
    .code>.SpecialComment,
    .code>.Debug {
     color: #777777;
    }
    .code>.Underlined {
     color: #00ff00;
     text-decoration: underline;
    }
    .code>.Ignore {
     color: #777777;
    }
    .code>.Error {
     color: #ff0000;
    }
    .code>.Todo {
     color: #0000ff;
    }
    .code>.Folded {
     color: #aaffff;
     background-color: #aaaaaa;
    }
    Internet Explorer6ではセレクタが正しく動作しないかと思いますので修正が必要です。
  • オプションをXHTML使用,CSS使用,PRE未使用モードに設定する
  • ~/_vimrc(un*xでは~/.vimrc)に以下を追加します。
    let g:use_xhtml = 1
    let g:html_use_css = 1
    let g:html_no_pre = 1
  • ソースコードをHTML化する
  • 全体をHTML出力するならば何も選択せず、また部分的にHTML出力するならば行選択(linewise-visual)して
    :TOHtml
    と実行します。
    HTMLには<html>や<body>も含まれますので、実際には<body>から</body>を切り取るといいでしょう。

これで色んなソースコードを皆に見てもらうことが出来るようになります。この方法はあくまでmattnが良いと思った方法ですので、もしかしたらより便利な方法があるかもしれません。
一度CSSさえ設定してあれば、上記の手順1つで簡単にHTML出力出来ます。ぜひコードを晒け出してみて下さい。

mattn the OSS fan.
Posted at by




コマンドモードで :help! 結果↓ E478: 慌てないでください!
tipsというよりイースターエッグかな...
Posted at by