llm-shell 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +61 -66
  3. data/lib/llm/shell/command.rb +40 -40
  4. data/lib/llm/shell/commands/clear_screen.rb +4 -18
  5. data/lib/llm/shell/commands/debug_mode.rb +12 -0
  6. data/lib/llm/shell/commands/dir_import.rb +4 -20
  7. data/lib/llm/shell/commands/disable_tool.rb +33 -0
  8. data/lib/llm/shell/commands/enable_tool.rb +33 -0
  9. data/lib/llm/shell/commands/file_import.rb +4 -20
  10. data/lib/llm/shell/commands/help.rb +23 -36
  11. data/lib/llm/shell/commands/show_chat.rb +4 -19
  12. data/lib/llm/shell/commands/show_version.rb +4 -20
  13. data/lib/llm/shell/commands/system_prompt.rb +4 -18
  14. data/lib/llm/shell/completion.rb +5 -5
  15. data/lib/llm/shell/config.rb +4 -5
  16. data/lib/llm/shell/formatter.rb +1 -2
  17. data/lib/llm/shell/internal/coderay/lib/coderay/duo.rb +81 -0
  18. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/_map.rb +17 -0
  19. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/comment_filter.rb +25 -0
  20. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/count.rb +39 -0
  21. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/debug.rb +49 -0
  22. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/debug_lint.rb +63 -0
  23. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/div.rb +23 -0
  24. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/encoder.rb +190 -0
  25. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/filter.rb +58 -0
  26. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/css.rb +65 -0
  27. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/numbering.rb +108 -0
  28. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html/output.rb +164 -0
  29. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/html.rb +333 -0
  30. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/json.rb +83 -0
  31. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/lines_of_code.rb +45 -0
  32. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/lint.rb +59 -0
  33. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/null.rb +18 -0
  34. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/page.rb +24 -0
  35. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/span.rb +23 -0
  36. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/statistic.rb +95 -0
  37. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/terminal.rb +195 -0
  38. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/text.rb +46 -0
  39. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/token_kind_filter.rb +111 -0
  40. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/xml.rb +72 -0
  41. data/lib/llm/shell/internal/coderay/lib/coderay/encoders/yaml.rb +50 -0
  42. data/lib/llm/shell/internal/coderay/lib/coderay/encoders.rb +18 -0
  43. data/lib/llm/shell/internal/coderay/lib/coderay/for_redcloth.rb +95 -0
  44. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/file_type.rb +151 -0
  45. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/plugin.rb +55 -0
  46. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/plugin_host.rb +221 -0
  47. data/lib/llm/shell/internal/coderay/lib/coderay/helpers/word_list.rb +72 -0
  48. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/_map.rb +24 -0
  49. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/c.rb +189 -0
  50. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/clojure.rb +217 -0
  51. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/cpp.rb +217 -0
  52. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/css.rb +196 -0
  53. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/debug.rb +75 -0
  54. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/delphi.rb +144 -0
  55. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/diff.rb +221 -0
  56. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/erb.rb +81 -0
  57. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/go.rb +208 -0
  58. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/groovy.rb +268 -0
  59. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/haml.rb +168 -0
  60. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/html.rb +275 -0
  61. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java/builtin_types.rb +421 -0
  62. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java.rb +174 -0
  63. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/java_script.rb +236 -0
  64. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/json.rb +98 -0
  65. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/lua.rb +280 -0
  66. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/php.rb +527 -0
  67. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/python.rb +287 -0
  68. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/raydebug.rb +75 -0
  69. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby/patterns.rb +178 -0
  70. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby/string_state.rb +79 -0
  71. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/ruby.rb +477 -0
  72. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/sass.rb +232 -0
  73. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/scanner.rb +337 -0
  74. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/sql.rb +169 -0
  75. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/taskpaper.rb +36 -0
  76. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/text.rb +26 -0
  77. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/xml.rb +17 -0
  78. data/lib/llm/shell/internal/coderay/lib/coderay/scanners/yaml.rb +140 -0
  79. data/lib/llm/shell/internal/coderay/lib/coderay/scanners.rb +27 -0
  80. data/lib/llm/shell/internal/coderay/lib/coderay/styles/_map.rb +7 -0
  81. data/lib/llm/shell/internal/coderay/lib/coderay/styles/alpha.rb +153 -0
  82. data/lib/llm/shell/internal/coderay/lib/coderay/styles/style.rb +18 -0
  83. data/lib/llm/shell/internal/coderay/lib/coderay/styles.rb +15 -0
  84. data/lib/llm/shell/internal/coderay/lib/coderay/token_kinds.rb +85 -0
  85. data/lib/llm/shell/internal/coderay/lib/coderay/tokens.rb +164 -0
  86. data/lib/llm/shell/internal/coderay/lib/coderay/tokens_proxy.rb +55 -0
  87. data/lib/llm/shell/internal/coderay/lib/coderay/version.rb +3 -0
  88. data/lib/llm/shell/internal/coderay/lib/coderay.rb +284 -0
  89. data/lib/llm/shell/internal/io-line/lib/io/line/multiple.rb +19 -0
  90. data/lib/{io → llm/shell/internal/io-line/lib/io}/line.rb +2 -0
  91. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/builder.rb +31 -0
  92. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/conversable.rb +37 -0
  93. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/prompt/completion.rb +49 -0
  94. data/lib/llm/shell/internal/llm.rb/lib/llm/bot/prompt/respond.rb +49 -0
  95. data/lib/llm/shell/internal/llm.rb/lib/llm/bot.rb +150 -0
  96. data/lib/llm/shell/internal/llm.rb/lib/llm/buffer.rb +162 -0
  97. data/lib/llm/shell/internal/llm.rb/lib/llm/client.rb +36 -0
  98. data/lib/llm/shell/internal/llm.rb/lib/llm/error.rb +49 -0
  99. data/lib/llm/shell/internal/llm.rb/lib/llm/eventhandler.rb +44 -0
  100. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream/event.rb +69 -0
  101. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream/parser.rb +88 -0
  102. data/lib/llm/shell/internal/llm.rb/lib/llm/eventstream.rb +8 -0
  103. data/lib/llm/shell/internal/llm.rb/lib/llm/file.rb +91 -0
  104. data/lib/llm/shell/internal/llm.rb/lib/llm/function.rb +177 -0
  105. data/lib/llm/shell/internal/llm.rb/lib/llm/message.rb +178 -0
  106. data/lib/llm/shell/internal/llm.rb/lib/llm/mime.rb +140 -0
  107. data/lib/llm/shell/internal/llm.rb/lib/llm/multipart.rb +101 -0
  108. data/lib/llm/shell/internal/llm.rb/lib/llm/object/builder.rb +38 -0
  109. data/lib/llm/shell/internal/llm.rb/lib/llm/object/kernel.rb +53 -0
  110. data/lib/llm/shell/internal/llm.rb/lib/llm/object.rb +89 -0
  111. data/lib/llm/shell/internal/llm.rb/lib/llm/provider.rb +352 -0
  112. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/error_handler.rb +36 -0
  113. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/files.rb +155 -0
  114. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/format/completion_format.rb +88 -0
  115. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/format.rb +29 -0
  116. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/models.rb +54 -0
  117. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/completion.rb +39 -0
  118. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/enumerable.rb +11 -0
  119. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/file.rb +23 -0
  120. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/response/web_search.rb +21 -0
  121. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic/stream_parser.rb +66 -0
  122. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/anthropic.rb +138 -0
  123. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek/format/completion_format.rb +68 -0
  124. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek/format.rb +27 -0
  125. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/deepseek.rb +75 -0
  126. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/audio.rb +73 -0
  127. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/error_handler.rb +47 -0
  128. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/files.rb +146 -0
  129. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/format/completion_format.rb +69 -0
  130. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/format.rb +39 -0
  131. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/images.rb +133 -0
  132. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/models.rb +60 -0
  133. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/completion.rb +35 -0
  134. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/embedding.rb +8 -0
  135. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/file.rb +11 -0
  136. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/files.rb +15 -0
  137. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/image.rb +31 -0
  138. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/models.rb +15 -0
  139. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/response/web_search.rb +22 -0
  140. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini/stream_parser.rb +86 -0
  141. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/gemini.rb +173 -0
  142. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/llamacpp.rb +74 -0
  143. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/error_handler.rb +36 -0
  144. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/format/completion_format.rb +77 -0
  145. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/format.rb +29 -0
  146. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/models.rb +56 -0
  147. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/response/completion.rb +28 -0
  148. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/response/embedding.rb +9 -0
  149. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama/stream_parser.rb +44 -0
  150. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/ollama.rb +116 -0
  151. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/audio.rb +91 -0
  152. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/error_handler.rb +46 -0
  153. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/files.rb +134 -0
  154. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/completion_format.rb +90 -0
  155. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/moderation_format.rb +35 -0
  156. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format/respond_format.rb +72 -0
  157. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/format.rb +54 -0
  158. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/images.rb +109 -0
  159. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/models.rb +55 -0
  160. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/moderations.rb +65 -0
  161. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/audio.rb +7 -0
  162. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/completion.rb +40 -0
  163. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/embedding.rb +9 -0
  164. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/enumerable.rb +23 -0
  165. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/file.rb +7 -0
  166. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/image.rb +16 -0
  167. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/moderations.rb +34 -0
  168. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/responds.rb +48 -0
  169. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/response/web_search.rb +21 -0
  170. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/responses/stream_parser.rb +76 -0
  171. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/responses.rb +99 -0
  172. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/stream_parser.rb +86 -0
  173. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai/vector_stores.rb +228 -0
  174. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/openai.rb +206 -0
  175. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/xai/images.rb +58 -0
  176. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/xai.rb +72 -0
  177. data/lib/llm/shell/internal/llm.rb/lib/llm/providers/zai.rb +74 -0
  178. data/lib/llm/shell/internal/llm.rb/lib/llm/response.rb +67 -0
  179. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/array.rb +26 -0
  180. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/boolean.rb +13 -0
  181. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/integer.rb +43 -0
  182. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/leaf.rb +78 -0
  183. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/null.rb +13 -0
  184. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/number.rb +43 -0
  185. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/object.rb +41 -0
  186. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/string.rb +34 -0
  187. data/lib/llm/shell/internal/llm.rb/lib/llm/schema/version.rb +8 -0
  188. data/lib/llm/shell/internal/llm.rb/lib/llm/schema.rb +81 -0
  189. data/lib/llm/shell/internal/llm.rb/lib/llm/server_tool.rb +32 -0
  190. data/lib/llm/shell/internal/llm.rb/lib/llm/tool/param.rb +75 -0
  191. data/lib/llm/shell/internal/llm.rb/lib/llm/tool.rb +78 -0
  192. data/lib/llm/shell/internal/llm.rb/lib/llm/utils.rb +19 -0
  193. data/lib/llm/shell/internal/llm.rb/lib/llm/version.rb +5 -0
  194. data/lib/llm/shell/internal/llm.rb/lib/llm.rb +121 -0
  195. data/lib/llm/shell/internal/optparse/lib/optionparser.rb +2 -0
  196. data/lib/llm/shell/internal/optparse/lib/optparse/ac.rb +70 -0
  197. data/lib/llm/shell/internal/optparse/lib/optparse/date.rb +18 -0
  198. data/lib/llm/shell/internal/optparse/lib/optparse/kwargs.rb +27 -0
  199. data/lib/llm/shell/internal/optparse/lib/optparse/shellwords.rb +7 -0
  200. data/lib/llm/shell/internal/optparse/lib/optparse/time.rb +11 -0
  201. data/lib/llm/shell/internal/optparse/lib/optparse/uri.rb +7 -0
  202. data/lib/llm/shell/internal/optparse/lib/optparse/version.rb +80 -0
  203. data/lib/llm/shell/internal/optparse/lib/optparse.rb +2469 -0
  204. data/lib/llm/shell/internal/paint/lib/paint/constants.rb +104 -0
  205. data/lib/llm/shell/internal/paint/lib/paint/pa.rb +13 -0
  206. data/lib/llm/shell/internal/paint/lib/paint/rgb_colors.rb +14 -0
  207. data/lib/llm/shell/internal/paint/lib/paint/shortcuts.rb +100 -0
  208. data/lib/llm/shell/internal/paint/lib/paint/shortcuts_version.rb +5 -0
  209. data/lib/llm/shell/internal/paint/lib/paint/util.rb +16 -0
  210. data/lib/llm/shell/internal/paint/lib/paint/version.rb +5 -0
  211. data/lib/llm/shell/internal/paint/lib/paint.rb +261 -0
  212. data/lib/llm/shell/internal/reline/lib/reline/config.rb +378 -0
  213. data/lib/llm/shell/internal/reline/lib/reline/face.rb +199 -0
  214. data/lib/llm/shell/internal/reline/lib/reline/history.rb +76 -0
  215. data/lib/llm/shell/internal/reline/lib/reline/io/ansi.rb +322 -0
  216. data/lib/llm/shell/internal/reline/lib/reline/io/dumb.rb +120 -0
  217. data/lib/llm/shell/internal/reline/lib/reline/io/windows.rb +530 -0
  218. data/lib/llm/shell/internal/reline/lib/reline/io.rb +55 -0
  219. data/lib/llm/shell/internal/reline/lib/reline/key_actor/base.rb +37 -0
  220. data/lib/llm/shell/internal/reline/lib/reline/key_actor/composite.rb +17 -0
  221. data/lib/llm/shell/internal/reline/lib/reline/key_actor/emacs.rb +517 -0
  222. data/lib/llm/shell/internal/reline/lib/reline/key_actor/vi_command.rb +518 -0
  223. data/lib/llm/shell/internal/reline/lib/reline/key_actor/vi_insert.rb +517 -0
  224. data/lib/llm/shell/internal/reline/lib/reline/key_actor.rb +8 -0
  225. data/lib/llm/shell/internal/reline/lib/reline/key_stroke.rb +119 -0
  226. data/lib/llm/shell/internal/reline/lib/reline/kill_ring.rb +125 -0
  227. data/lib/llm/shell/internal/reline/lib/reline/line_editor.rb +2356 -0
  228. data/lib/llm/shell/internal/reline/lib/reline/unicode/east_asian_width.rb +1292 -0
  229. data/lib/llm/shell/internal/reline/lib/reline/unicode.rb +421 -0
  230. data/lib/llm/shell/internal/reline/lib/reline/version.rb +3 -0
  231. data/lib/llm/shell/internal/reline/lib/reline.rb +527 -0
  232. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/generated_parser.rb +712 -0
  233. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/handler.rb +268 -0
  234. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_date.rb +35 -0
  235. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_date_time.rb +42 -0
  236. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/local_time.rb +40 -0
  237. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/parser.rb +21 -0
  238. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/scanner.rb +92 -0
  239. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/string_utils.rb +40 -0
  240. data/lib/llm/shell/internal/tomlrb/lib/tomlrb/version.rb +5 -0
  241. data/lib/llm/shell/internal/tomlrb/lib/tomlrb.rb +49 -0
  242. data/lib/llm/shell/options.rb +1 -1
  243. data/lib/llm/shell/renderer.rb +2 -3
  244. data/lib/llm/shell/repl.rb +21 -16
  245. data/lib/llm/shell/tool.rb +42 -0
  246. data/lib/llm/shell/tools/read_file.rb +15 -0
  247. data/lib/llm/shell/tools/system.rb +17 -0
  248. data/lib/llm/shell/tools/write_file.rb +16 -0
  249. data/lib/llm/shell/version.rb +1 -1
  250. data/lib/llm/shell.rb +83 -39
  251. data/libexec/llm-shell/shell +4 -6
  252. data/llm-shell.gemspec +0 -4
  253. metadata +233 -63
  254. data/lib/llm/function.rb +0 -17
  255. data/lib/llm/shell/command/extension.rb +0 -42
  256. data/lib/llm/shell/commands/utils.rb +0 -21
  257. data/lib/llm/shell/functions/read_file.rb +0 -22
  258. data/lib/llm/shell/functions/write_file.rb +0 -22
@@ -0,0 +1,530 @@
1
+ require 'fiddle/import'
2
+
3
+ class Reline::Windows < Reline::IO
4
+
5
+ attr_writer :output
6
+
7
+ def initialize
8
+ @input_buf = []
9
+ @output_buf = []
10
+
11
+ @output = STDOUT
12
+ @hsg = nil
13
+ @getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
14
+ @kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
15
+ @GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
16
+ @GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
17
+ @SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
18
+ @GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
19
+ @FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
20
+ @ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
21
+ @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
22
+ @hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
23
+ @GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
24
+ @ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
25
+ @GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
26
+ @GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
27
+ @FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
28
+ @SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
29
+
30
+ @GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
31
+ @SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
32
+ @WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
33
+
34
+ @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
35
+ end
36
+
37
+ def encoding
38
+ Encoding::UTF_8
39
+ end
40
+
41
+ def win?
42
+ true
43
+ end
44
+
45
+ def win_legacy_console?
46
+ @legacy_console
47
+ end
48
+
49
+ def set_default_key_bindings(config)
50
+ {
51
+ [224, 72] => :ed_prev_history, # ↑
52
+ [224, 80] => :ed_next_history, # ↓
53
+ [224, 77] => :ed_next_char, # →
54
+ [224, 75] => :ed_prev_char, # ←
55
+ [224, 83] => :key_delete, # Del
56
+ [224, 71] => :ed_move_to_beg, # Home
57
+ [224, 79] => :ed_move_to_end, # End
58
+ [ 0, 72] => :ed_prev_history, # ↑
59
+ [ 0, 80] => :ed_next_history, # ↓
60
+ [ 0, 77] => :ed_next_char, # →
61
+ [ 0, 75] => :ed_prev_char, # ←
62
+ [ 0, 83] => :key_delete, # Del
63
+ [ 0, 71] => :ed_move_to_beg, # Home
64
+ [ 0, 79] => :ed_move_to_end # End
65
+ }.each_pair do |key, func|
66
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
67
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
68
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
69
+ end
70
+
71
+ {
72
+ [27, 32] => :em_set_mark, # M-<space>
73
+ [24, 24] => :em_exchange_mark, # C-x C-x
74
+ }.each_pair do |key, func|
75
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
76
+ end
77
+
78
+ # Emulate ANSI key sequence.
79
+ {
80
+ [27, 91, 90] => :completion_journey_up, # S-Tab
81
+ }.each_pair do |key, func|
82
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
83
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
84
+ end
85
+ end
86
+
87
+ if defined? JRUBY_VERSION
88
+ require 'win32api'
89
+ else
90
+ class Win32API
91
+ DLL = {}
92
+ TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
93
+ POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
94
+
95
+ WIN32_TYPES = "VPpNnLlIi"
96
+ DL_TYPES = "0SSI"
97
+
98
+ def initialize(dllname, func, import, export = "0", calltype = :stdcall)
99
+ @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
100
+ import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
101
+ export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
102
+ calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
103
+
104
+ handle = DLL[dllname] ||=
105
+ begin
106
+ Fiddle.dlopen(dllname)
107
+ rescue Fiddle::DLError
108
+ raise unless File.extname(dllname).empty?
109
+ Fiddle.dlopen(dllname + ".dll")
110
+ end
111
+
112
+ @func = Fiddle::Function.new(handle[func], import, export, calltype)
113
+ rescue Fiddle::DLError => e
114
+ raise LoadError, e.message, e.backtrace
115
+ end
116
+
117
+ def call(*args)
118
+ import = @proto.split("")
119
+ args.each_with_index do |x, i|
120
+ args[i], = [x == 0 ? nil : +x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
121
+ args[i], = [x].pack("I").unpack("i") if import[i] == "I"
122
+ end
123
+ ret, = @func.call(*args)
124
+ return ret || 0
125
+ end
126
+ end
127
+ end
128
+
129
+ VK_RETURN = 0x0D
130
+ VK_MENU = 0x12 # ALT key
131
+ VK_LMENU = 0xA4
132
+ VK_CONTROL = 0x11
133
+ VK_SHIFT = 0x10
134
+ VK_DIVIDE = 0x6F
135
+
136
+ KEY_EVENT = 0x01
137
+ WINDOW_BUFFER_SIZE_EVENT = 0x04
138
+
139
+ CAPSLOCK_ON = 0x0080
140
+ ENHANCED_KEY = 0x0100
141
+ LEFT_ALT_PRESSED = 0x0002
142
+ LEFT_CTRL_PRESSED = 0x0008
143
+ NUMLOCK_ON = 0x0020
144
+ RIGHT_ALT_PRESSED = 0x0001
145
+ RIGHT_CTRL_PRESSED = 0x0004
146
+ SCROLLLOCK_ON = 0x0040
147
+ SHIFT_PRESSED = 0x0010
148
+
149
+ VK_TAB = 0x09
150
+ VK_END = 0x23
151
+ VK_HOME = 0x24
152
+ VK_LEFT = 0x25
153
+ VK_UP = 0x26
154
+ VK_RIGHT = 0x27
155
+ VK_DOWN = 0x28
156
+ VK_DELETE = 0x2E
157
+
158
+ STD_INPUT_HANDLE = -10
159
+ STD_OUTPUT_HANDLE = -11
160
+ FILE_TYPE_PIPE = 0x0003
161
+ FILE_NAME_INFO = 2
162
+ ENABLE_WRAP_AT_EOL_OUTPUT = 2
163
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
164
+
165
+ # Calling Win32API with console handle is reported to fail after executing some external command.
166
+ # We need to refresh console handle and retry the call again.
167
+ private def call_with_console_handle(win32func, *args)
168
+ val = win32func.call(@hConsoleHandle, *args)
169
+ return val if val != 0
170
+
171
+ @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
172
+ win32func.call(@hConsoleHandle, *args)
173
+ end
174
+
175
+ private def getconsolemode
176
+ mode = +"\0\0\0\0"
177
+ call_with_console_handle(@GetConsoleMode, mode)
178
+ mode.unpack1('L')
179
+ end
180
+
181
+ private def setconsolemode(mode)
182
+ call_with_console_handle(@SetConsoleMode, mode)
183
+ end
184
+
185
+ #if @legacy_console
186
+ # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
187
+ # @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
188
+ #end
189
+
190
+ def msys_tty?(io = @hConsoleInputHandle)
191
+ # check if fd is a pipe
192
+ if @GetFileType.call(io) != FILE_TYPE_PIPE
193
+ return false
194
+ end
195
+
196
+ bufsize = 1024
197
+ p_buffer = "\0" * bufsize
198
+ res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
199
+ return false if res == 0
200
+
201
+ # get pipe name: p_buffer layout is:
202
+ # struct _FILE_NAME_INFO {
203
+ # DWORD FileNameLength;
204
+ # WCHAR FileName[1];
205
+ # } FILE_NAME_INFO
206
+ len = p_buffer[0, 4].unpack1("L")
207
+ name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
208
+
209
+ # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
210
+ # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
211
+ name =~ /(msys-|cygwin-).*-pty/ ? true : false
212
+ end
213
+
214
+ KEY_MAP = [
215
+ # It's treated as Meta+Enter on Windows.
216
+ [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
217
+ [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
218
+
219
+ # It's treated as Meta+Space on Windows.
220
+ [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
221
+
222
+ # Emulate getwch() key sequences.
223
+ [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
224
+ [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
225
+ [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
226
+ [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
227
+ [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
228
+ [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
229
+ [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
230
+
231
+ # Emulate ANSI key sequence.
232
+ [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
233
+ ]
234
+
235
+ def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
236
+
237
+ # high-surrogate
238
+ if 0xD800 <= char_code and char_code <= 0xDBFF
239
+ @hsg = char_code
240
+ return
241
+ end
242
+ # low-surrogate
243
+ if 0xDC00 <= char_code and char_code <= 0xDFFF
244
+ if @hsg
245
+ char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
246
+ @hsg = nil
247
+ else
248
+ # no high-surrogate. ignored.
249
+ return
250
+ end
251
+ else
252
+ # ignore high-surrogate without low-surrogate if there
253
+ @hsg = nil
254
+ end
255
+
256
+ key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
257
+
258
+ match = KEY_MAP.find { |args,| key.match?(**args) }
259
+ unless match.nil?
260
+ @output_buf.concat(match.last)
261
+ return
262
+ end
263
+
264
+ # no char, only control keys
265
+ return if key.char_code == 0 and key.control_keys.any?
266
+
267
+ @output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
268
+
269
+ @output_buf.concat(key.char.bytes)
270
+ end
271
+
272
+ def check_input_event
273
+ num_of_events = 0.chr * 8
274
+ while @output_buf.empty?
275
+ Reline.core.line_editor.handle_signal
276
+ if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
277
+ # prevent for background consolemode change
278
+ @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
279
+ next
280
+ end
281
+ next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
282
+ input_records = 0.chr * 20 * 80
283
+ read_event = 0.chr * 4
284
+ if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
285
+ read_events = read_event.unpack1('L')
286
+ 0.upto(read_events) do |idx|
287
+ input_record = input_records[idx * 20, 20]
288
+ event = input_record[0, 2].unpack1('s*')
289
+ case event
290
+ when WINDOW_BUFFER_SIZE_EVENT
291
+ @winch_handler.()
292
+ when KEY_EVENT
293
+ key_down = input_record[4, 4].unpack1('l*')
294
+ repeat_count = input_record[8, 2].unpack1('s*')
295
+ virtual_key_code = input_record[10, 2].unpack1('s*')
296
+ virtual_scan_code = input_record[12, 2].unpack1('s*')
297
+ char_code = input_record[14, 2].unpack1('S*')
298
+ control_key_state = input_record[16, 2].unpack1('S*')
299
+ is_key_down = key_down.zero? ? false : true
300
+ if is_key_down
301
+ process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
302
+ end
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ def with_raw_input
310
+ yield
311
+ end
312
+
313
+ def write(string)
314
+ @output.write(string)
315
+ end
316
+
317
+ def buffered_output
318
+ yield
319
+ end
320
+
321
+ def getc(_timeout_second)
322
+ check_input_event
323
+ @output_buf.shift
324
+ end
325
+
326
+ def ungetc(c)
327
+ @output_buf.unshift(c)
328
+ end
329
+
330
+ def in_pasting?
331
+ not empty_buffer?
332
+ end
333
+
334
+ def empty_buffer?
335
+ if not @output_buf.empty?
336
+ false
337
+ elsif @kbhit.call == 0
338
+ true
339
+ else
340
+ false
341
+ end
342
+ end
343
+
344
+ def get_console_screen_buffer_info
345
+ # CONSOLE_SCREEN_BUFFER_INFO
346
+ # [ 0,2] dwSize.X
347
+ # [ 2,2] dwSize.Y
348
+ # [ 4,2] dwCursorPositions.X
349
+ # [ 6,2] dwCursorPositions.Y
350
+ # [ 8,2] wAttributes
351
+ # [10,2] srWindow.Left
352
+ # [12,2] srWindow.Top
353
+ # [14,2] srWindow.Right
354
+ # [16,2] srWindow.Bottom
355
+ # [18,2] dwMaximumWindowSize.X
356
+ # [20,2] dwMaximumWindowSize.Y
357
+ csbi = 0.chr * 22
358
+ if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) != 0
359
+ # returns [width, height, x, y, attributes, left, top, right, bottom]
360
+ csbi.unpack("s9")
361
+ else
362
+ return nil
363
+ end
364
+ end
365
+
366
+ ALTERNATIVE_CSBI = [80, 24, 0, 0, 7, 0, 0, 79, 23].freeze
367
+
368
+ def get_screen_size
369
+ width, _, _, _, _, _, top, _, bottom = get_console_screen_buffer_info || ALTERNATIVE_CSBI
370
+ [bottom - top + 1, width]
371
+ end
372
+
373
+ def cursor_pos
374
+ _, _, x, y, _, _, top, = get_console_screen_buffer_info || ALTERNATIVE_CSBI
375
+ Reline::CursorPos.new(x, y - top)
376
+ end
377
+
378
+ def move_cursor_column(val)
379
+ _, _, _, y, = get_console_screen_buffer_info
380
+ call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + val) if y
381
+ end
382
+
383
+ def move_cursor_up(val)
384
+ if val > 0
385
+ _, _, x, y, _, _, top, = get_console_screen_buffer_info
386
+ return unless y
387
+ y = (y - top) - val
388
+ y = 0 if y < 0
389
+ call_with_console_handle(@SetConsoleCursorPosition, (y + top) * 65536 + x)
390
+ elsif val < 0
391
+ move_cursor_down(-val)
392
+ end
393
+ end
394
+
395
+ def move_cursor_down(val)
396
+ if val > 0
397
+ _, _, x, y, _, _, top, _, bottom = get_console_screen_buffer_info
398
+ return unless y
399
+ screen_height = bottom - top
400
+ y = (y - top) + val
401
+ y = screen_height if y > screen_height
402
+ call_with_console_handle(@SetConsoleCursorPosition, (y + top) * 65536 + x)
403
+ elsif val < 0
404
+ move_cursor_up(-val)
405
+ end
406
+ end
407
+
408
+ def erase_after_cursor
409
+ width, _, x, y, attributes, = get_console_screen_buffer_info
410
+ return unless x
411
+ written = 0.chr * 4
412
+ call_with_console_handle(@FillConsoleOutputCharacter, 0x20, width - x, y * 65536 + x, written)
413
+ call_with_console_handle(@FillConsoleOutputAttribute, attributes, width - x, y * 65536 + x, written)
414
+ end
415
+
416
+ # This only works when the cursor is at the bottom of the scroll range
417
+ # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
418
+ def scroll_down(x)
419
+ return if x.zero?
420
+ # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
421
+ @output.write "\n" * x
422
+ end
423
+
424
+ def clear_screen
425
+ if @legacy_console
426
+ width, _, _, _, attributes, _, top, _, bottom = get_console_screen_buffer_info
427
+ return unless width
428
+ fill_length = width * (bottom - top + 1)
429
+ screen_topleft = top * 65536
430
+ written = 0.chr * 4
431
+ call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
432
+ call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
433
+ call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
434
+ else
435
+ @output.write "\e[2J" "\e[H"
436
+ end
437
+ end
438
+
439
+ def set_screen_size(rows, columns)
440
+ raise NotImplementedError
441
+ end
442
+
443
+ def hide_cursor
444
+ size = 100
445
+ visible = 0 # 0 means false
446
+ cursor_info = [size, visible].pack('Li')
447
+ call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
448
+ end
449
+
450
+ def show_cursor
451
+ size = 100
452
+ visible = 1 # 1 means true
453
+ cursor_info = [size, visible].pack('Li')
454
+ call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
455
+ end
456
+
457
+ def set_winch_handler(&handler)
458
+ @winch_handler = handler
459
+ end
460
+
461
+ def prep
462
+ # do nothing
463
+ nil
464
+ end
465
+
466
+ def deprep(otio)
467
+ # do nothing
468
+ end
469
+
470
+ def disable_auto_linewrap(setting = true, &block)
471
+ mode = getconsolemode
472
+ if 0 == (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
473
+ if block
474
+ begin
475
+ setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT)
476
+ block.call
477
+ ensure
478
+ setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT)
479
+ end
480
+ else
481
+ if setting
482
+ setconsolemode(mode & ~ENABLE_WRAP_AT_EOL_OUTPUT)
483
+ else
484
+ setconsolemode(mode | ENABLE_WRAP_AT_EOL_OUTPUT)
485
+ end
486
+ end
487
+ else
488
+ block.call if block
489
+ end
490
+ end
491
+
492
+ class KeyEventRecord
493
+
494
+ attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
495
+
496
+ def initialize(virtual_key_code, char_code, control_key_state)
497
+ @virtual_key_code = virtual_key_code
498
+ @char_code = char_code
499
+ @control_key_state = control_key_state
500
+ @enhanced = control_key_state & ENHANCED_KEY != 0
501
+
502
+ (@control_keys = []).tap do |control_keys|
503
+ # symbols must be sorted to make comparison is easier later on
504
+ control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
505
+ control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
506
+ control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
507
+ end.freeze
508
+ end
509
+
510
+ def char
511
+ @char_code.chr(Encoding::UTF_8)
512
+ end
513
+
514
+ def enhanced?
515
+ @enhanced
516
+ end
517
+
518
+ # Verifies if the arguments match with this key event.
519
+ # Nil arguments are ignored, but at least one must be passed as non-nil.
520
+ # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
521
+ def match?(control_keys: nil, virtual_key_code: nil, char_code: nil)
522
+ raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
523
+
524
+ (control_keys.nil? || [*control_keys].sort == @control_keys) &&
525
+ (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
526
+ (char_code.nil? || char_code == @char_code)
527
+ end
528
+
529
+ end
530
+ end
@@ -0,0 +1,55 @@
1
+
2
+ module Reline
3
+ class IO
4
+ RESET_COLOR = "\e[0m"
5
+
6
+ def self.decide_io_gate
7
+ if ENV['TERM'] == 'dumb'
8
+ Reline::Dumb.new
9
+ else
10
+ require 'reline/io/ansi'
11
+
12
+ case RbConfig::CONFIG['host_os']
13
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
14
+ require 'reline/io/windows'
15
+ io = Reline::Windows.new
16
+ if io.msys_tty?
17
+ Reline::ANSI.new
18
+ else
19
+ io
20
+ end
21
+ else
22
+ Reline::ANSI.new
23
+ end
24
+ end
25
+ end
26
+
27
+ def dumb?
28
+ false
29
+ end
30
+
31
+ def win?
32
+ false
33
+ end
34
+
35
+ def reset_color_sequence
36
+ self.class::RESET_COLOR
37
+ end
38
+
39
+ # Read a single encoding valid character from the input.
40
+ def read_single_char(timeout_second)
41
+ buffer = String.new(encoding: Encoding::ASCII_8BIT)
42
+ loop do
43
+ timeout = buffer.empty? ? Float::INFINITY : timeout_second
44
+ c = getc(timeout)
45
+ return unless c
46
+
47
+ buffer << c
48
+ encoded = buffer.dup.force_encoding(encoding)
49
+ return encoded if encoded.valid_encoding?
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ require 'reline/io/dumb'
@@ -0,0 +1,37 @@
1
+ class Reline::KeyActor::Base
2
+ def initialize(mappings = nil)
3
+ @matching_bytes = {}
4
+ @key_bindings = {}
5
+ add_mappings(mappings) if mappings
6
+ end
7
+
8
+ def add_mappings(mappings)
9
+ add([27], :ed_ignore)
10
+ 128.times do |key|
11
+ func = mappings[key]
12
+ meta_func = mappings[key | 0b10000000]
13
+ add([key], func) if func
14
+ add([27, key], meta_func) if meta_func
15
+ end
16
+ end
17
+
18
+ def add(key, func)
19
+ (1...key.size).each do |size|
20
+ @matching_bytes[key.take(size)] = true
21
+ end
22
+ @key_bindings[key] = func
23
+ end
24
+
25
+ def matching?(key)
26
+ @matching_bytes[key]
27
+ end
28
+
29
+ def get(key)
30
+ @key_bindings[key]
31
+ end
32
+
33
+ def clear
34
+ @matching_bytes.clear
35
+ @key_bindings.clear
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ class Reline::KeyActor::Composite
2
+ def initialize(key_actors)
3
+ @key_actors = key_actors
4
+ end
5
+
6
+ def matching?(key)
7
+ @key_actors.any? { |key_actor| key_actor.matching?(key) }
8
+ end
9
+
10
+ def get(key)
11
+ @key_actors.each do |key_actor|
12
+ func = key_actor.get(key)
13
+ return func if func
14
+ end
15
+ nil
16
+ end
17
+ end