nyagosで右プロンプトの表示とMercurial/Gitのブランチ表示

# (2015.06.05追記)
ふと気が付いたのですが`getStringWidth()`が全く不完全で、`á` `à` `â` `ä`などの文字も全角に判定されてしまい表示が崩れますね…
ちょっと調べるとUnicodeの全角/半角の文字の配置は結構バラバラの様で一文字ずつ判定するしかないようです。
Windowsなら`DrawText`の**DT_CALCRECT**で矩形範囲取得して計算できそうな気もします(やってない)。

# nyagos.getviewwidth()

nyagos 4.0.9_0から`nyagos.getviewwidth()`が追加されウィンドウの幅を取得できるようになりました。
というか、プルリクエスト送ってマージしてもらえましたｗ

ウィンドウの幅が分かることで、計算すれば**右プロンプト**的なことができますので
右プロンプトとしてMercurial/Gitのブランチ名を表示してみたいと思います。

こんな感じです
![snapshot-15-06-04-004204.png](https://qiita-image-store.s3.amazonaws.com/0/52493/3a1ec257-5ac9-42f3-b477-30d504b168a2.png)

# スクリプト
余計なもの(カレントディレクトリの下からn階層だけ取得する部分)を含んだため、ちょっと長くなってしまいました。

```lua:prompt.lua
local _prompt = nyagos.prompt
nyagos.prompt = function(template)
    return _prompt(makePrompt())
end

------------------------------------------------
-- PROMPT生成部分
function makePrompt()
    local prompt  = '$e[30;40;1m[' .. getCompressedPath(3):gsub('\\', '/') .. ']$e[37;1m'
    local hgbranch = nyagos.eval('hg branch 2> nul')
    local gitbranch = ''
    local gitbranch_tmp = nyagos.eval('git branch 2> nul')
    if (gitbranch_tmp ~= '') then
        gitbranch = gitbranch_tmp:match('%*%s(.[^\n]+)', 1)
    end
    local rprompt = ''
    if (hgbranch ~= '') then
        rprompt = rprompt .. '$e[30;40;1m[$e[33;40;1m' .. hgbranch .. '$e[30;40;1m]$e[37;1m'
    end
    if (gitbranch ~= '') then
        rprompt = rprompt .. '$e[30;40;1m[$e[33;40;1m' .. gitbranch .. '$e[30;40;1m]$e[37;1m'
    end
    local pad = nyagos.getviewwidth() - getStringWidth(removeEscapeSequence(prompt .. rprompt))
    for i = 1, pad-1 do
        prompt = prompt .. ' '
    end
    return prompt .. rprompt .. '\n$ '
end
------------------------------------------------

------------------------------------------------
-- 文字列の幅を取得
-- 半角文字:1, 全角文字:2 にカウント
function getStringWidth(src)
    local width = 0
    for p, c in utf8.codes(src) do
        if (0 ~= bit32.band(c, 0x7FFFFF80)) then
            if (0xFF61 <= c and c <= 0xFF9F) then
                width = width + 1
            else
                width = width + 2
            end
        else
            width = width + 1
        end
    end
    return width
end
------------------------------------------------

------------------------------------------------
-- エスケープシーケンスを削除
function removeEscapeSequence(src)
    -- FIXME : なぜか'$e%[(%d+;)+1m'でマッチしない
    return src:gsub('$e%[%d+;%d+;1m',''):gsub('$e%[%d+;1m','')
end

------------------------------------------------
-- 最下層nのディレクトリ名だけ表示する文字列生成
function getCompressedPath(num)
    local path = chomp(nyagos.eval('pwd'))
    local buff = path

    local drive = nil

    -- HOME以下の場合
    local home = nyagos.getenv("HOME") or nyagos.getenv("USERPROFILE")
    if path:find(home)then
        drive = '~'
        path = path:gsub(home, '~')
        buff = path
    end
    -- 通常のドライブ
    if drive == nil then
        drive = buff:match('(%w+:)\\')
        buff = buff:gsub('%w+:\\', '')
    end
    -- UNCパス
    if drive == nil then
        drive = buff:match('(\\\\.-)\\')
        buff = buff:gsub('\\\\.-\\', '')
    end

    local tbl = split(buff, "[\\/]")
    if #tbl > num then
        buff = "/..."
        for i = #tbl - (num - 1), #tbl do
            buff = buff .. '/' .. tbl[i]
        end
            path = drive .. buff
    end

    return path
end
------------------------------------------------

------------------------------------------------
-- srcの末尾から改行を取り除く
function chomp(src)
    return string.gsub(src, "[\r\n]+$", "")
end
------------------------------------------------

------------------------------------------------
-- strをpatで分割しテーブルを返す
-- code from 'http://lua-users.org/wiki/SplitJoin'
function split(str, pat)
    local t = {}  -- NOTE: use {n = 0} in Lua-5.0
    local fpat = "(.-)" .. pat
    local last_end = 1
    local s, e, cap = str:find(fpat, 1)
    while s do
        if s ~= 1 or cap ~= "" then
            table.insert(t, cap)
        end
        last_end = e+1
        s, e, cap = str:find(fpat, last_end)
    end
    if last_end <= #str then
        cap = str:sub(last_end)
        table.insert(t, cap)
    end
    return t
end
------------------------------------------------
```

# 既知の問題点
PROMPTの文字数を数えているため、`$P`のようなプロンプト表示時に展開されるような変数を使用すると表示が崩れます。
そのため、自前で展開済みの文字列を表示するよう手間が必要です。