Как работать с копировальной пастой в ncurses?

Кажется, ncurses обрабатывает вставку (из копии, вставляет), вставляя по одному символу за раз из текста, который был вставлен, что может быть медленным, если обработчик для каждого символа медленный. Я бы хотел обрабатывать события вставки самостоятельно, когда обнаружена последовательность вставки в скобках, начиная с ESC [200 ~ ( http://www.xfree86.org/current/ctlseqs.html).

2 ответа

Я подумал, что это работает после включения режима вставки в скобках, но это нужно делать с необработанными терминальными последовательностями, так как ncurses не предоставляет поддержки для этого сам по себе.

Вот код, иллюстрирующий «режим вставки в скобках» (с использованием проклятий Ruby).

Есть только три ключевых момента:

0.) Убедитесь, что ваш терминал поддерживает режим вставки в скобках (например, терминал Windows 10 примерно с 1 месяца, см. Https://github.com/microsoft/terminal/releases/tag/v1.7.572.0 )

1.) Включите режим вставки в скобках в терминале, отправив ?2004h CSI.

      print("\x1b[?2004h")

2.) Когда происходит паста, узнайте, что вы получили \x1b[200~ чтобы начать разбор вставленного текста и \x1b[201~ чтобы распознать, что вставленный текст закончен.

      # /usr/bin/ruby2.7
require "curses"
include Curses

def main_loop
  init_screen
  noecho      # Disable Echoing of character presses

  # Switch on braketed paste mode
  print("\x1b[?2004h")

  addstr("Please paste something into this terminal (make sure it supports braketed paste!) or press 'q' to quit.\n")

  loop do
    c = get_char2

    case c
    in 'q' # use q to quit
      return

    in csi: "200~" # Bracketed paste started

      pasted = ""
      loop do
        d = get_char2
        case d
        in csi: "201~" # Bracketed paste ended
          break
        else
          pasted += d
        end
      end

      addstr("You pasted: #{pasted.inspect}\n")

    else
      addstr("You didn't paste something, you entered: #{c.inspect} #{c.class.name}\n")
    end
  end

ensure
  close_screen
end

#
# For CSI, or "Control Sequence Introducer" commands,
# the ESC [ is followed by
# 1.) any number (including none) of "parameter bytes" in the range
#     0x30–0x3F (ASCII 0–9:;<=>?), then by
# 2.) any number of "intermediate bytes" in the range
#     0x20–0x2F (ASCII space and !"#$%&'()*+,-./), then finally by
# 3.) a single "final byte" in the range
#     0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).
#
# From: https://handwiki.org/wiki/ANSI_escape_code
def get_csi

  result = ""
  loop do
    c = get_char
    result += c
    if c.ord >= 0x40 && c.ord <= 0x7E
      return result
    end
  end
end

# Just like get_char, but will read \x1b[<csi> and return it as a hash { csi: ... }, everything else is just returned as-is
def get_char2
  c = get_char
  case c
  when "\e" # ESC
    case get_char
    when '['
      return { csi: get_csi }
    else
      raise "¯\_(ツ)_/¯"
    end
  else
    return c
  end
end

main_loop()
Другие вопросы по тегам