kitty.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright 2024 Henrique Paone
  2. #
  3. # This file is part of Kitty-Tui.
  4. #
  5. # Kitty-Tui is free software: you can redistribute it and/or modify it under the
  6. # terms of the GNU General Public License as published by the Free Software
  7. # Foundation, either version 3 of the License, or (at your option) any later
  8. # version.
  9. #
  10. # Kitty-Tui is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12. # PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License along with
  15. # Kitty-Tui. If not, see <https://www.gnu.org/licenses/>.
  16. require_relative './tables.rb'
  17. module Kitty
  18. # Note: The order of these two constants are important for the translate_bits
  19. # function. Do not change it
  20. Modifiers = [ 'A', '', 'T', 'C', 'A', 'S']
  21. Kitty_flags = {
  22. :associated_text => 16,
  23. :all_escaped => 8,
  24. :alternate_keys => 4,
  25. :event_types => 2,
  26. :disambiguate_escape_codes => 1
  27. }
  28. Kitty_builtin_regex = /\x1b\]133;[ABC]\x1b\\/
  29. # Fetch and parse KITTY_PIPE_DATA set by kitty
  30. def get_kitty_data
  31. kitty_data = /(\d+):(\d+,?\d+):(\d+,?\d+)/.match ENV['KITTY_PIPE_DATA']
  32. scrolled = kitty_data[1].to_i
  33. cline, ccol = kitty_data[2].split(',').reverse.map! do |e| e.to_i end
  34. lines, cols = kitty_data[3].split(',').map! do |e| e.to_i end
  35. { scrolled: scrolled, cline: cline, ccol: ccol, lines: lines, cols: cols }
  36. end
  37. def hi_line(line, cstart, cend, color)
  38. printf "\e[2*x\e[%d;%d;%d;%d;48;5;#{ color }$r\e[*x", line, cstart, line, cend, color
  39. end
  40. def unscroll(amt)
  41. print "\e[#{ amt }+T"
  42. end
  43. def translate_bits(num, reference_array)
  44. translation = []
  45. bits = num.bit_length
  46. reference = reference_array.last(bits).reverse
  47. bits.downto 0 do |i|
  48. translation << reference[i] if num[i] == 1
  49. end
  50. translation
  51. end
  52. def kitty_query_keyboard_flags
  53. print "\e[?u"
  54. flags = translate_bits(get_escaped.first[1..-1].to_i, Kitty_flags.values)
  55. enabled = []
  56. Kitty_flags.each_pair do |k, v|
  57. enabled << k if flags.include?(v)
  58. end
  59. enabled
  60. end
  61. def kitty_keyboard_enable(*options)
  62. flags = []
  63. options.each do |opts|
  64. flags << Kitty_flags[opts ]if Kitty_flags.include? opts
  65. end
  66. print "\e[>#{ flags.sum }u"
  67. end
  68. def kitty_restore
  69. print "\e[<u"
  70. end
  71. # gets an escaped sequence terminated in either u or ~. this is specially
  72. # useful for getting input when using the flag disambiguate_escape_codes
  73. def get_escaped
  74. is_arrow = false
  75. escaped = ''
  76. loop do
  77. c = STDIN.getch
  78. break if ['u', '~'].include? c
  79. escaped += c
  80. if ('A'..'D').include? c
  81. is_arrow = true
  82. break
  83. end
  84. end
  85. has_mod = escaped.count(';') >= 1
  86. escaped =
  87. if is_arrow and has_mod
  88. escaped[(escaped.index(';') + 1..-1)].insert 1, ';'
  89. else escaped[2..-1]
  90. end.split ';'
  91. if is_arrow and has_mod
  92. escaped[0] = escaped[0].to_i
  93. escaped.reverse!
  94. end
  95. escaped
  96. end
  97. # This converts an escaped sequence using vi-like notation, for example, if
  98. # the user press ctrl+t, the function outputs <C-t>. Note that this requires
  99. # the disambiguate_escape_codes flag to be set in kitty
  100. def parse_escaped(escaped)
  101. ignore_shift = is_letter = false
  102. codepoint, mods, assoc_codep = escaped
  103. mods = mods.to_i - 1
  104. return nil if Ignore.include? codepoint
  105. key = if Functional_keys.include? codepoint
  106. Functional_keys[codepoint]
  107. else
  108. is_letter = true
  109. if codepoint == assoc_codep or assoc_codep.nil?
  110. '' << codepoint.to_i
  111. else
  112. ignore_shift = true
  113. '' << assoc_codep.to_i
  114. end
  115. end
  116. modifiers = []
  117. unless mods < 1
  118. modifiers = translate_bits(mods, Modifiers)
  119. modifiers.delete 'S' if ignore_shift
  120. end
  121. if modifiers.empty?
  122. is_letter ? key : "<#{ key }>"
  123. else
  124. "<#{ modifiers.join '-' }-#{ key }>"
  125. end
  126. end
  127. end