UWSCのコマンドラインインタプリタ

しゅんさんのUWSCインタープリターの二番煎じさ

uwscli

動機:CLIでやりたかった、しかもカラフルにしたかった

#help って打つとヘルプ見れる
#window って打つとウィンドウのIDとタイトルとクラス名を列挙する
#exit か ×ボタンで終わる
式を入力すると実行される

複数行入力とかねー、最初はあったんだけどどのみちeval()ちゃんがどうにも出来ないのでやめた

#から始まる独自コマンドなんかはtab補完してみたかったけど、いやーどうしたらいいかわかんなかったわー
ReadConsoleInputでキー入力見ながら~WriteConsoleInput?WriteConsoleOutput?かなんかする?
それ以前にINPUT_RECORD構造体で断念してんだけどな!

式の戻り値そのままコンソールに出力するのとかは気に入ってる

Interpreter.Run()

module Interpreter

    // 予約済み変数
    dim a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
    dim id, ie
    hashtbl hash
    dim array[0]

    procedure Run()
        dim __ret, __cmd
        CLI.Create()
        while TRUE
            CLI.Output("> ", FALSE)
            __cmd = CLI.Input()
            select TRUE
                case pos("#", __cmd) = 1
                    if Command(__cmd) then break
                default
                    try
                        __ret = eval(__cmd)
                        select __ret
                            case EMPTY
                                CLI.Output("  EMPTY", TRUE, CLI.GetColor("lb"))
                            case NULL
                                CLI.Output("  NULL", TRUE, CLI.GetColor("lb"))
                            case NOTHING
                                CLI.Output("  NOTHING", TRUE, CLI.GetColor("lb"))
                            case "", "__cmd"
                                // do nothing
                            default
                                CLI.Output( "  " + __ret )
                        selend
                        __ret = ""
                    except
                        CLI.Error("  " + TRY_ERRMSG)
                    endtry
            selend
            ctrlwin(CLI.ID(), ACTIVATE)
        wend
        CLI.Destroy()
    fend

    function Command(cmd)
        dim i, id, cmds
        result = FALSE
        cmds = split(cmd, " ", TRUE)
        select TRUE
            case cmds[0] = "#exit"
                if length(cmds) > 1 then
                    result = TRUE
                else
                    CLI.Output("終了しますか? (y/n): ", FALSE)
                    result = CLI.Input() = "y"
                endif
            case cmds[0] = "#window"
                if length(cmds) > 1 then
                    listAllWindows = val(cmds[1], 1)
                else
                    listAllWindows = FALSE
                endif
                CLI.Output("ID    Title / Class", TRUE)
                CLI.Output(format("-", CLI.GetConsoleWidth() - 1), TRUE)
                for i = 0 to getallwin() - 1
                    id = ALL_WIN_ID[i]
                    if ! listAllWindows and ! status(id, ST_VISIBLE) then continue
                    CLI.Output(format(id, 4), FALSE)
                    CLI.Output(format(" ", 2) + status(id, ST_TITLE), TRUE)
                    CLI.Output(format(" ", 6) + status(id, ST_CLASS), TRUE)
                next
            case cmds[0] = "#enum"
                if length(cmds) > 1 then
                    try
                        for i = 0 to eval("length(" + cmds[1] + ")") - 1
                            if cmds[1] = "hash"
                                CLI.Output( "hash[<#DBL>" + hash[i, HASH_KEY] + "<#DBL>] = " + hash[i, HASH_VAL] )
                            else
                                CLI.Output(cmds[1] + "[" + i + "] = " + eval(cmds[1] + "[" + i + "]"))
                            endif
                        next
                    except
                        CLI.Error("  " + TRY_ERRMSG)
                    endtry
                endif
            case cmds[0] = "#help"
                Help()
            default
                CLI.Output("不正なコマンド: ", FALSE, CLI.GetColor("p"))
                CLI.Output(cmd)
                CLI.Output()
                CLI.Output("ヘルプを参照しますか? (y/n): ", FALSE)
                if CLI.Input() = "y" then
                    Help()
                endif
        selend
    fend

    procedure Help()
        CLI.Output()
        CLI.Output("※使い方", TRUE, CLI.GetColor("lb"))
        CLI.Output("  式を入力すると実行します")
        CLI.Output("  式の戻り値はコンソールに表示されます")
        CLI.Output()
        CLI.Output("※変数について", TRUE, CLI.GetColor("lb"))
        CLI.Output("  以下の変数が使用可能です", TRUE)
        CLI.Output("  a b c d e f g h i j k l m", TRUE, CLI.GetColor("y"))
        CLI.Output("  n o p q r s t u v w x y z", TRUE, CLI.GetColor("y"))
        CLI.Output("  id ie", TRUE, CLI.GetColor("y"))
        CLI.Output("  array", FALSE, CLI.GetColor("y"))
        CLI.Output(" (サイズ1の配列、resizeして使って下さい)")
        CLI.Output("  hash ", FALSE, CLI.GetColor("y"))
        CLI.Output(" (連想配列)", TRUE)
        CLI.Output("  変数への代入は ", FALSE)
        CLI.Output(":=", FALSE, CLI.GetColor("y"))
        CLI.Output(" を使用してください ")
        CLI.Output()
        CLI.Output("※特殊コマンド一覧", TRUE, CLI.GetColor("lb"))
        CLI.Output("#help", TRUE, CLI.GetColor("y"))
        CLI.Output("   このヘルプを表示します", TRUE)
        CLI.Output("#window [all]", TRUE, CLI.GetColor("y"))
        CLI.Output("   ウィンドウIDを列挙、オプション指定で非表示ウィンドウも列挙します", TRUE)
        CLI.Output("#enum 配列名", TRUE, CLI.GetColor("y"))
        CLI.Output("   配列の内容を列挙します", TRUE)
        CLI.Output("#exit [silent]", TRUE, CLI.GetColor("y"))
        CLI.Output("   " + GET_UWSC_NAME + "を終了します、オプション指定で確認なしで終了", TRUE)
        CLI.Output()
    fend

endmodule

module CLI
    dim hInput, hOutput, hError
    dim orgTextAttr = 0
    dim FOREGROUND_ORIGINAL, BACKGROUND_ORIGINAL
    dim id = -1

    function Create(title = GET_UWSC_NAME)
        result = AllocConsole()
        ifb result then
            SetConsoleTitleA(title)
            hInput  = GetStdHandle(STD_INPUT_HANDLE)
            hOutput = GetStdHandle(STD_OUTPUT_HANDLE)
            hError  = GetStdHandle(STD_ERROR_HANDLE)
            orgTextAttr = getOriginalTextAttribute()
            BACKGROUND_ORIGINAL = orgTextAttr and $F0
            FOREGROUND_ORIGINAL = orgTextAttr and $F
            id = getid(title, "ConsoleWindowClass")
        endif
    fend

    function ID()
        result = id
    fend

    function GetColor(fgcolor = "", bgcolor = "")
        f = _color(fgcolor)
        if f < 0 then f = FOREGROUND_ORIGINAL
        b = _color(bgcolor)
        if b < 0 then b = BACKGROUND_ORIGINAL else b = b * $10
        result = f or b
    fend

    function _color(color = "")
        select color
            case "blue", "b"
                result = FOREGROUND_BLUE or FOREGROUND_INTENSITY
            case "green", "g"
                result = FOREGROUND_GREEN or FOREGROUND_INTENSITY
            case "red", "r"
                result = FOREGROUND_RED or FOREGROUND_INTENSITY
            case "yellow", "y"
                result = FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
            case "yellow-", "y-"
                result = FOREGROUND_GREEN or FOREGROUND_RED
            case "pink", "p"
                result = FOREGROUND_BLUE or FOREGROUND_RED or FOREGROUND_INTENSITY
            case "lightblue", "lb"
                result = FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_INTENSITY
            case "white", "w"
                result = FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY
            case "black", "bl", "bk"
                result = 0
            case "gray", "gy"
                result = FOREGROUND_INTENSITY
            default
                result = -1
        selend
    fend

    function Destroy()
        result = FreeConsole()
    fend

    function Output(Text = "", Cr = TRUE, color = -1)
        if Cr then Text = Text + "<#CR>"
        if length(Text) then
            dim size
            if color > -1 then SetConsoleTextAttribute(hOutput, color)
            result = WriteConsoleA(hOutput, Text, lengthb(Text), size, 0)
            if color > -1 then SetConsoleTextAttribute(hOutput, orgTextAttr)
        endif
    fend

    function Input(BufferSize = 1024)
        dim size
        result = format(chr(0), BufferSize)
        ifb ReadConsoleA(hInput, result, BufferSize, size, 0) then
            result = replace(result, "<#cr>", "")
        endif
    fend

    function Error(Text)
        dim size
        Text = Text + "<#CR>"
        SetConsoleTextAttribute(hError, GetColor("r"))
        result = WriteConsoleA(hError, Text, lengthb(Text), size, 0)
        SetConsoleTextAttribute(hError, orgTextAttr)
    fend

    function getConsoleScreenBufferInfoArray()
        result = safearray(0, 10)
        GetConsoleScreenBufferInfo(hOutput, result)
    fend

    function getOriginalTextAttribute()
        CONSOLE_SCREEN_BUFFER_INFO = getConsoleScreenBufferInfoArray()
        result = CONSOLE_SCREEN_BUFFER_INFO[4]
    fend

    function GetConsoleWidth()
        CONSOLE_SCREEN_BUFFER_INFO = getConsoleScreenBufferInfoArray()
        result = CONSOLE_SCREEN_BUFFER_INFO[0]
    fend

    def_dll AllocConsole():bool:kernel32
    def_dll FreeConsole():bool:kernel32
    def_dll GetStdHandle(dword):dword:kernel32
    def_dll ReadConsoleA(dword, var string, dword, var dword, dword):bool:kernel32
    def_dll WriteConsoleA(dword, string, dword, var dword, dword):bool:kernel32
    def_dll SetConsoleTitleA(string):bool:kernel32
    def_dll SetConsoleTextAttribute(dword, int):bool:kernel32
    def_dll GetConsoleScreenBufferInfo(hwnd, word[]):bool:kernel32.dll

    const STD_INPUT_HANDLE  = -10   //標準入力ハンドルを取得
    const STD_OUTPUT_HANDLE = -11   //標準出力ハンドルを取得
    const STD_ERROR_HANDLE  = -12   //標準エラーハンドルを取得

    const FOREGROUND_BLUE      = $1  //文字色に青を加える
    const FOREGROUND_GREEN     = $2  //文字色に緑を加える
    const FOREGROUND_RED       = $4  //文字色に赤を加える
    const FOREGROUND_INTENSITY = $8  //文字色を高輝度にする
    const BACKGROUND_BLUE      = $10 //背景色に青を加える
    const BACKGROUND_GREEN     = $20 //背景色に緑を加える
    const BACKGROUND_RED       = $40 //背景色に赤を加える
    const BACKGROUND_INTENSITY = $80 //背景色を高輝度にする

endmodule

UWSCのコマンドラインインタプリタ」への2件のフィードバック

  1. ピンバック: PowerShellから対話形式でUWSCを動かすモジュールできた | たっぷす庵

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中