run_ctrlsk = proc (e: env, c: char) signals (errmsg(string), stop(env, string)) help_msg1 = "@,?w: move to end of # previous word\n" || "A,?x: move backward # pages\n" || "B,?r: move forward # pages\n" || "C,?v: move right # words\n" || "D,?t: move left # word\n" || "H: enter alternate keypad mode\n" || "J: pattern search # times for default\n" || "L,?q: delete backward to end of # previous word\n" || "M,?s: delete forward to start of # next word\n" || "N,?y: move to start of # next word\n" norm_msg = "P: delete forward # words\n" || "Q: delete backward # words\n" swap_msg = "P: delete backward # words\n" || "Q: delete forward # words\n" help_msg2 = "R: forward string search # times for default\n" || "S,?p: backward string search # times for default\n" || "T: set case mode for searches\n" || "U: scroll window up # lines\n" || "V: scroll window down # lines\n" || "W: reposition window at cursor\n" || "?n: exit to EXEC\n" || "?u: exit alternate keypad mode\n" || "?M: garbage collect address space\n" || "&c: scroll window to button position\n" || "&C: set cursor to button position\n" || "&t: (#<1: normal, #=1: underline, #>1: invert) between cursor and mouse\n" || "&T: set mark to button position\n" || "&w: move to button window cursor\n" || "&W: move to button window\n" || "&Y: insert cut buffer |#| times (#<0: before cursor)\n" || "&z: store saved text in cut buffer\n" || "&Z: store deleted text in cut buffer\n" || "esc: redefine escape sequence" prompt1 = "Escape: " prompt2 = "Escape: ?" prompt3 = "Escape: [" prompt4 = "Escape: O" own any_defs: bool := false own redefs: string own qredefs: string own swapped: bool := false if c = ctrlat then prompt = "Set red & blue function keys" legal = "RS" help = "R: reset to normal mode\n" || "S: swap meanings" i: int, opt: char := get_option (e, prompt, legal, help, false) swapped := opt = 'S' return end resignal errmsg b: buf := e.buffer arg: int := e.this_arg line, pos: int := buf$get_cursor(b) dotop: bool := false prompt: string := prompt1 qmark: bool := false xmark: bool := false while true do if ~dotop then dotop := ~_pending_wait() end if dotop then top_display(e, prompt) env$display(e) end c := _getc() if xmark cand c >= 'a' cand c <= 'z' then qmark := true end if dotop then top_display(e, string$append(prompt, c)) end if any_defs cand ((~qmark cand string$indexc(c, redefs) > 0) cor (qmark cand string$indexc(c, qredefs) > 0)) then s: string if qmark then s := "esc-?" else s := "esc-" end s := env$fetch_str(e, string$append(s, c), "") env$forget_char(e) for i: int in int$from_to_by(arg, 1, -1) do _push_macro_chars(s) end return end if (~qmark cand (c = 'A' cor c = 'B')) cor (qmark cand (c = 'x' cor c = 'r')) then % move up/down arg pages if c = 'A' cor c = 'x' then arg := - arg end env$move_window(e, arg) elseif (~qmark cand (c = 'C' cor c = 'D')) cor (qmark cand (c = 'v' cor c = 't')) then % move right/left # words if c = 'D' cor c = 't' then arg := - arg end line, pos := scan_word(b, line, pos, arg, false, e.word_chars) buf$set_cursor(b, line, pos) elseif (~qmark cand (c = '@' cor c = 'N')) cor (qmark cand (c = 'w' cor c = 'y')) then % move right/left # start/end words if c = '@' cor c = 'w' then arg := - arg end line, pos := scan_word(b, line, pos, arg, true, e.word_chars) buf$set_cursor(b, line, pos) elseif ~qmark cand c = 'H' then % enter alternate keypad mode if _set_keypad_mode(true) then top_display(e, "Entering Alternate Keypad Mode.") env$store_num(e, "keypad", 1) end elseif ~qmark cand c = 'J' then % pattern search # times obj: string := env$fetch_str(e, "psearch", "") case: bool := env$fetch_num(e, "ignore_case", 0) = 0 confirm: bool := env$fetch_num(e, "pconfirm", 0) ~= 0 immed: bool := false if arg < 0 then immed := true arg := -arg end for arg in int$from_to_by(arg, 1, -1) do if ~pattern$search(e, obj, case, immed, confirm) then signal errmsg("Not found!") end end elseif (~qmark cand (c = 'L' cor c = 'M')) cor (qmark cand (c = 'q' cor c = 's')) then % delete left/right # end/start words if c = 'L' cor c = 'q' then arg := -arg end line, pos := scan_word(b, line, pos, arg, true, e.word_chars) env$delete1(e, line, pos) elseif ~qmark cand (c = 'P' cor c = 'Q') then % delete left/right # words if (c = 'P' cand swapped) cor (c = 'Q' cand ~swapped) then arg := -arg end line, pos := scan_word(b, line, pos, arg, false, e.word_chars) env$delete1(e, line, pos) elseif (~qmark cand (c = 'R' cor c = 'S')) cor (qmark cand c = 'p') then % search left/right # times if c ~= 'R' then arg := - arg end if ~string_search(e.buffer, env$fetch_str(e, "search", ""), arg, env$fetch_num(e, "ignore_case", 0) = 0) then signal errmsg("Not found!") end elseif ~qmark cand c = 'T' then % set case mode arg := 0 if mconfirm(e, "Ignore upper/lower case in searches", true) then arg := 1 end env$store_num(e, "ignore_case", arg) elseif ~qmark cand (c = 'U' cor c = 'V') then % scroll up/down if c = 'U' then arg := -arg end pos := env$choose_window(e) + arg if line < pos then if arg = -1 cor arg = 1 then _bell() end pos := line elseif line >= pos + e.size then if arg = -1 cor arg = 1 then _bell() end pos := line - e.size + 1 end e.window_top := pos elseif ~qmark cand c = 'W' then % reposition at cursor env$new_window(e) elseif qmark cand (c = 'M' cor c = 'n') then % enter EXEC or GC e.this_arg := 1 if c = 'M' then e.this_arg := 4 end run_ctrlat(e, ctrlat) elseif qmark cand c = 'u' then % exit alternate keypad mode if _set_keypad_mode(false) then top_display(e, "Leaving Alternate Keypad Mode.") env$store_num(e, "keypad", 0) end elseif c = '?' then % read next char or print help if ~qmark cand ~xmark then qmark := true prompt := prompt2 continue end help: string := norm_msg if swapped then help := swap_msg end type_string(e, help_msg1 || help || help_msg2, "---- Help for escape sequences") dotop := true xmark := false qmark := false prompt := prompt1 continue elseif c = '[' cand ~xmark cand ~qmark then xmark := true prompt := prompt3 continue elseif c = 'O' cand ~xmark cand ~qmark then xmark := true prompt := prompt4 continue elseif c = esc cand ~qmark cand ~xmark then % redefine escape sequence prompt := "Define escape: " while true do if ~_in_macro() then top_display(e, prompt) env$display(e) end c := _getc() prompt := string$append(prompt, c) if qmark cor xmark then break elseif c = '?' then qmark := true elseif c = '[' cor c = 'O' then xmark := true else break end end if ~_in_macro() then top_display(e, prompt) end if env$is_argenv(e) then signal errmsg("Can't redefine now!") end if xmark cand c >= 'a' cand c <= 'z' then qmark := true end if (~qmark cand c = esc) cor (qmark cand c = '?') then signal errmsg("Can't redefine this sequence!") end if ~any_defs then redefs := "" qredefs := "" end name, defs: string if qmark then name := string$append("esc-?", c) defs := qredefs else name := string$append("esc-", c) defs := redefs end s: string := get_string_arg(e, "Define as", env$fetch_str(e, name, "")) env$store_str(e, name, s) arg := string$indexc(c, defs) if string$empty(s) then if arg > 0 then defs := string$substr(defs, 1, arg - 1) || string$rest(defs, arg + 1) any_defs := ~string$empty(redefs) cor ~string$empty(qredefs) end elseif arg = 0 then defs := string$append(defs, c) any_defs := true end if qmark then qredefs := defs else redefs := defs end elseif (c = '\303' cor c = '\324') cand ~qmark cand ~xmark then hpos, vpos: int := input$bpos() lines, chars: int := _get_screen_size() if vpos <= e.top_line cor vpos > e.last_line cor hpos < 0 cor hpos >= chars then signal errmsg("Position lies outside window") end vpos := vpos - e.top_line + e.window_top - 1 s: string := b[vpos] i: int := int$max(hpos + 2, string$size(s) + 1) while _calc_hpos(s, i) > hpos do i := i - 1 end if c = '\303' then buf$set_cursor(b, vpos, i) else buf$set_mark(b, vpos, i) end elseif (c = '\327' cor c = '\343' cor c = '\367') cand ~qmark cand ~xmark then hpos, vpos: int := input$bpos() lines, chars: int := _get_screen_size() for ee: env in winset$displayed() do if vpos <= ee.top_line cor vpos > ee.last_line cor hpos < 0 cor hpos >= chars cor (env$is_argenv(e) cand e ~= ee) then continue end if c = '\343' then if e ~= ee then break end e.window_top := line + e.top_line + 1 - vpos return end if c = '\327' then env$choose_cursor(ee) end signal stop(ee, "") end signal errmsg("Position lies outside window") elseif c = '\331' cand ~qmark cand ~xmark then s: string := x_fetch_cut(0) if string$empty(s) then return end for i: int in int$from_to_by(int$abs(arg), 1, -1) do if ~env$insert1(e, s) then signal errmsg("Can't insert text here!") end end if arg > 0 then buf$set_cursor(b, line, pos) end elseif (c = '\332' cor c = '\372') cand ~qmark cand ~xmark then cut: buf if c = '\332' then cut := e.killed else cut := e.saved end buf$set_cursor(cut, 1, 1) x_store_cut(0, buf$b2s(cut, buf$size(cut), max_int)) buf$set_cursor(cut, 1, 1) elseif c = '\364' cand ~qmark cand ~xmark then input$set_highlight(arg > 0) screen$set_highlight(arg > 0, arg > 1) elseif ((c >= '\301' cand c <= '\330') cor (c >= '\341' cand c <= '\370')) cand ~qmark cand ~xmark then return elseif c = ctrlg then % quit signal errmsg(quit_msg) else signal errmsg("Illegal escape char: '" || c2s(c) || "'") end resignal errmsg return end end run_ctrlsk