Extract duplicated UTF-8 codepoint-to-bytes encoding into a shared
function in src/string.c. Update all gems to use it:
- mruby-sprintf: %c specifier
- mruby-io: putc
- mruby-string-ext: Integer#chr
- mruby-pack: pack("U")
- mruby-compiler: Unicode escapes in parser
Also use existing mrb_utf8len() in io.c for character length detection.
Co-authored-by: Claude <noreply@anthropic.com>
For integer arguments, encode UTF-8 directly into a stack buffer
instead of creating a temporary mrb_value string via mrb_str_new()
or calling Integer#chr.
- ~5% faster for single %c
- ~15% faster for multiple %c in one format string
- fixes UTF-8 characters (>= 0x80) which previously raised RangeError
Co-authored-by: Claude <noreply@anthropic.com>
IO#putc writes a single character without intermediate string allocation.
- Integer argument: writes byte value (mod 256)
- String argument: writes first character (UTF-8 aware when MRB_UTF8_STRING)
- Returns the argument (IO#putc) or nil (Kernel#putc, matching CRuby)
This provides ~44% memory reduction for character-by-character output
compared to printf "%c" or print ch.chr approaches.
Co-authored-by: Claude <noreply@anthropic.com>
add support for automatic dedentation when typing 'in' at the
beginning of a line, matching the behavior of 'when' for pattern
matching case/in expressions.
Co-authored-by: Claude <noreply@anthropic.com>
pattern matching is now implemented with support for:
- case/in syntax with multiple in-clauses
- array patterns with rest (*) and post-rest elements
- hash patterns with shorthand and rest (**)
- guard clauses (if/unless)
- alternative patterns (|)
- pin operator (^)
- as pattern (=>)
- one-line pattern matching (expr in pat, expr => pat)
- NoMatchingPatternError exception
Co-authored-by: Claude <noreply@anthropic.com>
add support for find patterns in case/in expressions:
- [*pre, elem, *post] - find elem anywhere in array
- [*, elem, *] - anonymous rest (discarded)
- [*pre, a, b, *post] - multiple middle elements
implementation includes:
- grammar rules for find patterns with p_args, p_rest in parse.y
- NODE_PAT_FIND codegen with iterative search loop
- pre/post variable binding via range slicing
- p_const rule to prevent conflict with array literals
Co-authored-by: Claude <noreply@anthropic.com>
add comprehensive tests for pattern matching features:
- basic case/in with literals and variables
- array patterns with rest and nested structures
- hash patterns with shorthand and rest
- guard clauses (if/unless)
- alternative patterns (|)
- pin operator (^)
- as pattern (=>)
- one-line pattern matching (in and =>)
- NoMatchingPatternError handling
Co-authored-by: Claude <noreply@anthropic.com>
add support for one-line pattern matching syntax:
- 'expr in pattern' returns true/false
- 'expr => pattern' raises NoMatchingPatternError on mismatch
add NODE_MATCH_PAT node type for both forms, distinguished by
raise_on_fail flag. grammar rules placed at expr level to avoid
conflict with rescue clause's exception variable syntax.
Co-authored-by: Claude <noreply@anthropic.com>
Add support for brace-less hash patterns at top level of case/in.
`in a: x, b: y` is now equivalent to `in {a: x, b: y}`.
`in a:, b:` shorthand now works with newlines (CRuby compatible).
Changes:
- Add EXPR_VALUE to IS_LABEL_POSSIBLE() to recognize labels after `in`
- Add brace-less hash pattern rules to p_expr
- Change p_hash_elem to use p_as instead of p_expr to avoid recursion
- Add in_kwarg flag to parser state for pattern matching context
- Set in_kwarg in lexer when keyword_in is returned
- Use EXPR_ARG after tLABEL_TAG when in_kwarg is set (makes newlines significant)
Co-authored-by: Claude <noreply@anthropic.com>
Add pin operator `^var` that matches against existing variable values
instead of creating new bindings. Also add bracket-less array pattern
syntax at top level: `in 1, 2, x` is equivalent to `in [1, 2, x]`.
Co-authored-by: Claude <noreply@anthropic.com>
Add support for hash patterns in pattern matching expressions:
- {key:} shorthand binds to variable with same name
- {key: pattern} matches key against pattern
- {**rest} captures remaining keys
- {**nil} requires exact match (no extra keys)
- {**} ignores extra keys without capturing
Parser adds new grammar rules (p_hash, p_hash_body, p_hash_elems,
p_hash_elem, p_kwrest) and new_pat_hash() constructor.
Codegen generates code to call deconstruct_keys on the target hash,
then iterates through key-pattern pairs to match each key's value.
Adds Hash#deconstruct_keys method that returns self for pattern matching.
Co-authored-by: Claude <noreply@anthropic.com>
Add support for if/unless guards in case/in pattern matching:
case value
in x if x > 0 then :positive
in x unless x == 0 then :non_zero
end
Uses modifier_if/modifier_unless tokens since guards appear after
an expression. Disable peephole optimization for pattern variable
binding to prevent gen_move() from being optimized away when failed
guard jumps target the binding instruction.
Co-authored-by: Claude <noreply@anthropic.com>
Implement Phase 1 of Ruby pattern matching:
- value patterns (literals, constants, nil/true/false)
- variable patterns (binds matched value)
- alternative patterns (pat1 | pat2)
- as patterns (pattern => var)
Pattern matching uses === operator for value comparison,
allowing type checking with class patterns (e.g., in Integer).
Co-authored-by: Claude <noreply@anthropic.com>
Before inserting a newline, re-indent the current line to match
the expected indent level. This fixes cases where the user typed
with incorrect indentation.
Co-authored-by: Claude <noreply@anthropic.com>
When TAB triggers auto-indentation, preserve the cursor's relative
position within the line instead of moving it to the indent boundary.
Co-authored-by: Claude <noreply@anthropic.com>
Instead of just removing 2 spaces, perform_dedent() now calculates
the expected indent level from previous lines and aligns to that.
Co-authored-by: Claude <noreply@anthropic.com>
Extend auto-dedent to trigger when typing dedent keywords, not just
end and }. Now dedent occurs when completing: else, elsif, when,
rescue, ensure.
Co-authored-by: Claude <noreply@anthropic.com>
When splitting a line with Enter, check if the new line starts with
a dedenting keyword (end, else, elsif, when, rescue, ensure, }) and
reduce indentation by one level.
Co-authored-by: Claude <noreply@anthropic.com>
TAB now performs auto-indentation instead of completion when:
- cursor is at start of line
- cursor is at end of line
- character before cursor is whitespace
Auto-indent calculates expected indent level from previous lines
and adjusts current line. Dedenting keywords (end, else, elsif,
when, rescue, ensure, }) reduce indent by one level.
Co-authored-by: Claude <noreply@anthropic.com>
when pressing Ctrl+K on an empty line, delete the entire line instead
of doing nothing. this makes it easier to clean up empty lines while
editing multi-line input.
Co-authored-by: Claude <noreply@anthropic.com>
pressing Enter in the middle of multi-line input now always inserts
a new line instead of evaluating, even if the code is syntactically
complete. evaluation only occurs when cursor is at the end of the
last line.
Co-authored-by: Claude <noreply@anthropic.com>
- restore mirb_completion.c/h from before readline removal
- add editor adapter for tab completion (mirb_setup_editor_completion,
mirb_get_completions, mirb_free_completions)
- add TAB key handling in mirb_editor.c
- fix string literal completion: properly detect when cursor is outside
a string by scanning forward, allow string/array/hash literals as
safe receivers for method completion
Co-authored-by: Claude <noreply@anthropic.com>
- fix Enter in middle of line with trailing blank continuation line:
now properly splits the line and removes redundant blank line
- fix auto-indentation when inserting in middle of existing code:
calculate indent from lines up to cursor, not entire buffer
- add mirb_buffer_delete_line() for removing lines from buffer
Co-authored-by: Claude <noreply@anthropic.com>
Previously, all continuation lines showed the same line number (e.g.,
"1*" for every line). Now each line shows its actual line number:
1> class Foo
2* def bar
3* end
4* end
Add mirb_editor_set_prompt_format() which accepts printf-style format
strings (e.g., "%d> ", "%d* ") and calculates the correct prompt length
for each line to ensure proper cursor positioning.
Co-authored-by: Claude <noreply@anthropic.com>
Add in-memory command history for mirb sessions:
- Up arrow on first line: navigate to older history entries
- Down arrow on last line: navigate to newer history entries
- Current input is preserved when browsing and restored when
navigating past the newest entry
- History uses a circular buffer (100 entries max)
- Duplicate consecutive entries are not added
Co-authored-by: Claude <noreply@anthropic.com>
Headers in mrbgems are now categorized into three types:
- src/*.h: gem internal only
- include/*.h: inter-gem use (visible to dependent gems)
- include/export/*.h: external API (exported via mruby-config --cflags)
This prevents internal headers like *_hal.h from being exposed to
external users while maintaining inter-gem header accessibility.
Co-authored-by: Claude <noreply@anthropic.com>
Remove readline/linenoise dependency and implement custom multi-line
editor with:
- Terminal raw mode handling (POSIX termios)
- Multi-line buffer with cursor navigation
- Auto-indentation for Ruby blocks
- Auto-dedentation when typing 'end' or '}'
- Natural terminal scrolling behavior
- Emacs-style keybindings (Ctrl+A/E/K/U/W/Y, Alt+B/F/D)
This eliminates GPL licensing concerns from readline while providing
better multi-line editing than the previous single-line implementation.
The MRUBY_MIRB_READLINE environment variable is no longer supported
as readline integration has been completely removed; ref #6626
Co-authored-by: Claude <noreply@anthropic.com>
Add ANSI color support to mirb for better visual distinction:
- green prompts (both ready '>' and continuation '*')
- red error messages (syntax errors, runtime errors, warnings)
- bold result indicator ('=>')
Colors are automatically disabled when:
- output is not a TTY
- TERM is unset or "dumb"
- NO_COLOR environment variable is set
Co-authored-by: Claude <noreply@anthropic.com>
- automatically indent continuation lines based on block depth
- detect block-opening keywords (def, class, if, do, etc.) and braces
- use ANSI escape sequences to fix indentation for:
- block-closing keywords (end, })
- mid-block keywords (else, elsif, rescue, ensure, when)
- only active for interactive TTY input with ANSI support
- requires GNU readline (not available with linenoise)
Co-authored-by: Claude <noreply@anthropic.com>