2008/01/31


最近Plaggerにハマってるからって、やる事メチャメチャやな...

Plaggerのフィードをvimの「--remote-send」を使って転送するPlaggerプラグインを作りました。
vimには、リモートサーバと言う機能があり以下のオプション/コマンドで別に起動しているvimへコマンド/式/ファイルを送信する事が出来ます。

--remote [+{cmd}] {file} ...
別のサーバへファイルを送信します。
+{cmd}により開く際にコマンドを併用出来ます。
--remote-silent [+{cmd}] {file} ...
--remote と同等ですが、エラー等が発生してもメッセージ出力されません。
--remote-wait [+{cmd}] {file} ...
--remote と同等ですが、送信したvimが終了するまで待機します。
vimで編集した結果をどこかに送るシェルスクリプト等では使えるかもしれません。
--remote-wait-silent [+{cmd}] {file} ...
--remote-wait と同等ですが、エラー等が発生してもメッセージ出力されません。
--remote-tab [+{cmd}] {file} ...
--remote と似ていますが、指定されたファイルを全て別タブで開きます。
--remote-tab-silent [+{cmd}] {file} ...
--remote-tab と同等ですが、エラー等が発生してもメッセージ出力されません。
--remote-tab-wait [+{cmd}] {file} ...
--remote-tab と同等ですが、送信したvimが終了するまで待機します。
--remote-tab-wait-silent [+{cmd}] {file} ...
--remote-tab-wait と同等ですが、エラー等が発生してもメッセージ出力されません。
--servername {name}
リモートサーバを名称で指定します。リモートサーバ一覧を取得するには --serverlist を使用します。
--remote-send {keys}
リモートサーバにキーを送ります。基本的にnormalコマンドで与える引数と同等です。
--remote-expr {expr}
リモートサーバに式を送り、その結果を出力します。
--serverlist
リモートサーバ一覧を出力します。

その他、スクリプトから使える
remote_expr({server}, {string} [, {idvar}])
{server}に対して{string}という式を評価して貰います。
:echo remote_expr("gvim", "2+2") と書くと4が表示されます。
remote_foreground({server})
{server}をフォアグラウンドにします。 remote_expr({server}, "foreground()") と同等の機能ですね。
等がありますので、vimを起動しなくても色々な事が出来ます。

今日は、はてなブックマークから「vim」タグが付いているエントリをvimに転送するPlaggerプラグインを作りました。
確認はWindowsでしかしてませんが、X Windowが動いている環境や、Mac OS X等でも動くかと思います。
※あと、フィードタイトルにエスケープ文字や「<ESC>」等といったvimのキー識別ぽい物があると動かない可能性があります。 package Plagger::Plugin::Publish::Vim;
use strict;
use base qw( Plagger::Plugin );

our $VERSION = '0.01';

use Encode;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'plugin.init' => \&initialize,
        'publish.entry' => \&add_entry,
    );
}

sub initialize {
    my($self,$context) = @_;

    $self->{vim} = $self->conf->{vim};
    $self->{vim} = "vim" if (!$self->{vim});
    $self->{server} = $self->conf->{server};
    if (!$self->{server}) {
        open(IN, "vim --serverlist|");
        $self->{server} = <IN>;
        close(IN);
        chomp $self->{server};
    }
    open(IN, sprintf("%s --servername %s --remote-expr \"&encoding\"|",
        $self->{vim}, $self->{server}));
    $self->{encoding} = <IN>;
    print $self->{encoding}."\n";
    close(IN);
    my $command = sprintf("%s --servername %s --remote-send \"<C-\\\><C-N>:new<CR>i\"",
        $self->{vim}, $self->{server});
    system($command);
}

sub add_entry {
    my($self, $context, $args) = @_;

    $context->log(info => $self->{server});
    my $command = sprintf("%s --servername %s --remote-send \"%s\n\t%s\n<C-W>\"",
        $self->{vim}, $self->{server},
        encode($self->{encoding} || 'utf8', $args->{entry}->{title}),
        encode($self->{encoding} || 'utf8', $args->{entry}->{link}),
    );
    system($command);
}

1;
で、YAMLはこんな感じ
global:
  assets_path: /home/user/plagger/assets
  timezone: Asia/Tokyo
  log:
    level: info

plugins:
  - module: Subscription::Config
    config:
      feed:
        - http://b.hatena.ne.jp/t/vim?mode=rss

  - module: Filter::BreakEntriesToFeeds
    config:
      use_entry_title: 1

  - module: Publish::Vim
    config:
      #vim: vim7
      #server: GVIM1
実行結果は
vim_plagger

またくだらんもん作ってしもた...
Posted at by




vimscriptの発祥から考えると、vimで扱えるオブジェクトはあくまで数値、文字列レベルの物でしかないと思われがちですが、Dictionaryとfunction()を使えば、それとなく継承ぽい事が出来ます。
まぁ、javascriptに近い言語仕様というのもありますからね。
以下のコードでは、簡単なクラスとオブジェクトを定義しています。
function! Class_Prototype() dict
  return self
endfunction

function! Class_Override(...) dict
  if a:0 == 0|throw "Invalid Parameter"|endif
  let class = copy(self)
  let class.__NAME__ = a:1
  if type(a:2) == type(class.New)
    let class.New = a:2
  else
    let class.New = self.New
  endif
  let class.Super = self
  return class
endfunction

function! Class_New(...) dict
  let instance = copy(self)
  call remove(instance, "New")
  call remove(instance, "Override")
  let instance.Super = self
  return instance
endfunction

function! Class_ToString() dict
    return self.__NAME__
endfunction

let Object = {
 \ "__NAME__" : "Object",
 \ "Prototype"function("Class_Prototype"),
 \ "Override"function("Class_Override"),
 \ "Super"{},
 \ "New"function("Class_New"),
 \ "ToString"function("Class_ToString")}
この状態で if exists("object")|unlet object|endif
let object = Object.New()
echo object.ToString() . ":..."
とすると Object:... と表示されます。

ここで function! Human_Sing() dict
  return self.perfix . "は" . self.name . "。" . self.title
endfunction
function! Human_New(...) dict
  let instance = copy(self)
  let instance.perfix = a:1
  let instance.name = a:2
  let instance.title = a:3
  let instance.Sing = function("Human_Sing")
  return instance
endfunction
let Human = Object.Override("Human", function("Human_New"))
とすると、Objectクラスを継承するHumanクラスを定義する事が出来ます。
さらにこの状態で if exists("human")|unlet human|endif
let human = Human.New("私", "人間", "一般人")
echo human.ToString() . ":" . human.Sing()
とすると Human:私は人間。一般人 と表示されます。
つまり、Newメソッドをオーバーライドし、Singメソッドを追加した事になります。ToStringメソッドはObjectクラスのメソッドとなります。
vimscriptはJavascriptのように、メンバを動的に生成出来ますので
function! Gian_Boxing(who) dict
  return a:who . "のくせに生意気だぞ!!!"
endfunction
let Gian = Human.Override("Gian", {})
let Gian.Boxing = function("Gian_Boxing")
if exists("gian")|unlet gian|endif
let gian = Gian.New("俺", "ジャイアン", "ガキ大将")
echo gian.ToString() . ":" . gian.Sing()
echo gian.Boxing("のび太")
とすると Gian:俺はジャイアン。ガキ大将
のび太のくせに生意気だぞ!!!
とジャイアンが生成出来ます。
意外とやれるもんですね。

ただ、せっかくローカルスコープ、スクリプトスコープ、グローバルスコープ等、名前空間は既にしっかり存在してるんだから、もう少し他のオブジェクト指向言語(JavaやJavaString、C#やVB.NET)のように既定メソッドとかデフォルトコンストラクタみたいな概念が欲しいなぁ...
あと関数名は先頭大文字強制ってのは痛い。
ま、その辺はまた今度...

mattn the vimscripter
Posted at by




vimのtipsに何かいいのがないか探してたら...
:help scroll-smooth なんてのを発見。

中身みたら...
==============================================================================
Smooth scrolling                                        *scroll-smooth*

If you like the scrolling to go a bit smoother, you can use these mappings: >
        :map <C-U> <C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y>
        :map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>

(Type this literally, make sure the '<' flag is not in 'cpoptions').

==============================================================================
と...

まぁスムースですわな。
書いた奴出て来い
Posted at by