rebolesc-key

Is it possible to detect esc key with ask function?


Would like to detect esc key to escape the forever loop in pseudo code:

forever [ url: ask "Url: " if (url = esc) [ break ] ]

Is this possible ?


Solution

  • There is no simple answer, you must use own console-port to handle it correctly, here is the part of it taken from one of my old projects:

    REBOL [title: "Console port"]
    
    set 'ctx-console make object! [
        system/console/busy: none
        system/console/break: false
        buffer: make string! 512
        history: system/console/history
        prompt: "## " ;system/console/prompt
        spec-char: none
        port: none
        init: func[][
            port: open/binary [scheme: 'console]
            set 's-print get in system/words 'print
            set 's-prin  get in system/words 'prin
            set 'prin func[msg /err /inf /user user-data][
                ctx-console/clear-line
                s-prin reform msg
                ctx-console/print-line
            ]
            set 'print func[msg /err /inf /user user-data][
                prin rejoin [reform msg newline]
            ]
            s-prin prompt
        ]
        print-line: func[][
            s-prin rejoin [ prompt head buffer "^(1B)[" length? buffer "D"]
        ]
        clear-line: func[][
            s-prin rejoin [
                "^(1B)[" (
                (index? buffer) +
                (length? prompt) +
                (length? buffer))
                "D^(1B)[K"
            ]
        ]
        key-actions: make block! [
            #{08} [;BACK
                if 0 < length? head buffer [
                    buffer: remove back buffer
                    s-prin rejoin [
                        "^(back)^(1B)[K"
                        buffer
                        "^(1B)["
                        length? buffer "D"
                    ]
                ]
            ]
            #{7E} [;HOME
                s-prin rejoin ["^(1B)[" (index? buffer) - 1 "D"]
                buffer: head buffer
            ]
            #{7F} [;DELETE
                buffer: remove buffer
                s-prin rejoin ["^(1B)[K" buffer "^(1B)[" length? buffer "D"]
            ]
            #{1B} [;ESCAPE
                spec-char: copy/part port 1
                either spec-char = #{1B} [
                    print "ESCAPE"
                    clear-line
                    set 'print :s-print
                    set 'prin  :s-prin
                    system/console/break: true
                    on-escape
                ][
                    switch append spec-char copy/part port 1 [
                        #{5B41} [;ARROW UP
                            if not tail? history [
                                clear-line
                                clear head buffer
                                s-prin join prompt buffer: copy history/1
                                history: next history
                                buffer: tail buffer
                            ]
                        ]
                        #{5B42} [;ARROW DOWN
                            clear-line
                            buffer: head buffer
                            clear buffer
                            if all [
                                not error? try [history: back history]
                                not none? history/1
                            ] [
                                buffer: copy history/1
                            ]
                            s-prin join prompt buffer
                            buffer: tail buffer
                        ]
                        #{5B43} [;ARROW RIGHT
                            if not tail? buffer [
                                s-prin "^(1B)[C"
                                buffer: next buffer
                            ]
                        ]
                        #{5B44} [;ARROW LEFT
                            if 1 < index? buffer [
                                s-prin "^(1B)[D"
                                buffer: back buffer
                            ]
                        ]
                    ]
                ]
            ]
        ]
        do-command: func[comm /local e][
            set/any 'e attempt compose [do (comm)]
    
            if all [
                not unset? 'e
                value? 'e
                not object? :e
                not port? :e
                not function? :e
            ][
                print head clear skip rejoin [system/console/result mold :e] 127
                if (length? mold :e) > 127 [
                    print "...^/"
                ]
            ]
        ]
        on-enter: func[input-str /local e][
            print rejoin [system/console/prompt input-str]
            do-command input-str
        ]
        on-escape: func[][halt]
        process: func[/local ch c tmp spec-char err][
            ch: to-char pick port 1
            either (ch = newline) or (ch = #"^M") [;ENTER
                tmp: copy head buffer
                if empty? tmp [return none]
                history: head history
                if any [empty? history tmp <> first history ] [
                    insert history tmp
                ]
                clear-line
                buffer: head buffer
                clear buffer
                print-line
                on-enter tmp
            ][
                switch/default to-binary ch key-actions [
                    either tail? buffer [
                        s-prin ch ;either local-echo [ch]["*"]
                    ][
                        s-prin rejoin ["^(1B)[@" ch]
                    ]
                    buffer: insert buffer ch
                ]
            ]
        ]
    ]
    ctx-console/init
    
    ;and now do something with your own console:
    wait-list: reduce [ctx-console/port]
    forever [
        attempt [ready: wait/all wait-list]
        if ready [
            ctx-console/process
        ]
    ]
    

    You will probably like to change the ctx-console/on-escape and ctx-console/on-enter functions.