implements context-aware tab completion for mirb supporting all readline
variants (GNU readline, libedit, linenoise) with graceful degradation
when no readline library is available.
completion features:
- method names on objects (e.g., "hello".re<Tab> completes to reverse, replace)
- local variables from compiler context
- global variables via Ruby introspection
- constants and class names
- Ruby keywords
architecture:
- core completion engine is library-agnostic
- thin adapters for readline/libedit and linenoise
- context detection based on cursor position analysis
- safe receiver evaluation with exception handling
- proper word break characters so "String.new" works correctly
implementation adds:
- mirb_completion.h: interface definitions and data structures
- mirb_completion.c: complete implementation (~670 lines)
- mirb.c: integration with setup/cleanup calls
Co-authored-by: Claude <noreply@anthropic.com>
addresses #6626 where users building portable binaries need explicit control
over readline detection instead of auto-detection.
MRUBY_MIRB_READLINE values:
auto (default) - auto-detect: try readline, then edit, then linenoise
readline, gnu - force GNU readline only
edit, libedit - force libedit only
linenoise - force linenoise only
none, off, false, disabled - use plain input mode (no readline)
close#6626
Co-authored-by: Claude <noreply@anthropic.com>
runtime errors now distinguish between:
- errors in current input: show relative line number
- errors from previously defined methods: show method context
examples:
1> a.foo
line 1: undefined method 'a' for Object (NoMethodError)
1> def foo
2* bar
3* end
1> foo
(mirb):in foo: undefined method 'bar' for Object (NoMethodError)
this provides better context since method name is more useful
than line number for errors in previously defined code
Co-authored-by: Claude <noreply@anthropic.com>
syntax errors now show:
- line:column format with relative line numbers (matching prompt)
- source line from user input
- caret indicator pointing to error position
example:
1> x = @@@
line 1:6: syntax error, unexpected invalid token
x = @@@
^
multi-line example:
1> class Foo
2* def bar
3* x = @@@
line 3:6: syntax error, unexpected invalid token
x = @@@
^
Co-authored-by: Claude <noreply@anthropic.com>
add minimal line number decoration to prompts to help track position
within multi-line code blocks. format is 'N>' for initial line and
'N*' for continuation lines. line counter resets after each complete
evaluation for clarity and minimal visual noise.
example:
1> def foo
2* x = 1
3* end
=> :foo
1> 1 + 1
=> 2
Co-authored-by: Claude <noreply@anthropic.com>
since all current uses check for failure (!MRB_OPEN_SUCCESS), add
MRB_OPEN_FAILURE() as the primary macro for better readability. define
MRB_OPEN_SUCCESS() in terms of MRB_OPEN_FAILURE() to avoid duplication
and optimize the common case. update all usage sites to use the clearer
MRB_OPEN_FAILURE() form.
Co-authored-by: Claude <noreply@anthropic.com>
made mrb_print_error() handle NULL by printing "Failed to allocate
mrb_state" when mrb is NULL. since mrb_close() already handles NULL,
this allows simplified error checking pattern:
if (!MRB_OPEN_SUCCESS(mrb)) {
mrb_print_error(mrb); // handles NULL
mrb_close(mrb); // handles NULL
return EXIT_FAILURE;
}
updated all binary tools (mruby, mirb, mrdb, mrbtest) to use this
simplified pattern, removing nested if checks.
Co-authored-by: Claude <noreply@anthropic.com>
changed mrb_open() and mrb_open_core() to return mrb_state with mrb->exc
set (instead of NULL) when initialization fails. this allows callers to
programmatically inspect error details, which is essential for embedded
systems without stderr. return NULL only for true allocation failure.
added MRB_OPEN_SUCCESS(mrb) macro to check initialization success, since
mrb != NULL no longer guarantees success. updated all binary tools
(mruby, mirb, mrdb, mrbtest) to use new pattern: check MRB_OPEN_SUCCESS,
print exception details via mrb_print_error if available, then mrb_close.
mrb_core_init_protect now preserves exception in mrb->exc instead of
printing and clearing it, giving caller control over error handling.
breaking change: callers must use MRB_OPEN_SUCCESS(mrb) or check both
mrb != NULL && mrb->exc == NULL. old NULL-only checks will miss
initialization failures.
Co-authored-by: Claude <noreply@anthropic.com>
The build configuration for `mruby` assumes only the `ncurses` library
needs to be linked because `tinfo` is implicitly pulled in.
In environments where ncurses is available only as a static library,
`tinfo` needs to be linked explicitly (needed for functions like
`tputs`.
This patch fixes that by linking `tinfo` if available.
It also fixes the build for environments where only the `ncursesw`
version of the library (including wide character support) is present,
while still giving preference to the `ncurses` version (without wide
character support).
The `REnv` object is difficult to deal with, and it would be ideal if the user did not have to manipulate it directly.
In some previous situations, it was necessary to call `mrb_env_unshare()`, a non-API function, after `mrb_load_string()` or similar.
With this patch, it is no longer necessary for users to use `mrb_env_unshare()` directly, as it is now handled internally simply by using the `mrb_vm_ci_env_clear()` function.
Also, `mrb_vm_ci_env_set()` is demoted from the `MRB_API` function for the same reason.
ref. commit 1ab3da6f08
Exception raising can now be controlled by the caller.
The main purpose on this patch is:
- Suppress exceptions from `obj_free()` in `src/gc.c` with `mrb_env_unshare()`.
- Consider the possibility that calls to `mrb_malloc()` may cause `e` objects to be subject to GC.
When control is returned to `mrb_env_unshare()`, `struct free_obj::next` in the same offset as `struct REnv::stack` is rewritten.
Unexpected results then occur when the object is reused.
Also, if `mrb_heap_page` containing an `e` object is freed, it may cause `SIGSEGV` at that point.
- Protects the value of the stack on `callinfo` that just exits if GC occurs inside `mrb_env_unshare()`.
```ruby
def m
b = -> { b }
end
p m.call
# => print block object, not nil
```
This patch does not raise a `NoMemoryError` exception in `mrb_env_unshare()` and can detect that error.
Thus, the problem fixed in # 3087 is not resurrected.
Also, it may seem that this patch should suppress exceptions raised by `cipop()` during `mrb_protect_error()` and `mrb_vm_exec()` unwinds.
However, `mrb_callinfo::u.env` by `CINFO_DIRECT` is not seen to be set.
So in that case `mrb_env_unshare()` is assumed to be originally exception-free.
Instead of including `mruby/presym.h` everywhere, we provided the
fallback `mruby/presym.inc` under `include/mruby` directory, and specify
`-I<build-dir>/include` before `-I<top-dir>/include` in `presym.rake`.
So even when someone drops `-I<build-dir>/include` in compiler options,
it just compiles without failure.
This enhances self-containment.
Previously `mrb_context::stack` had the current call level stack, but now it owns it.
The `mrb_context::stack` field, which is no longer needed, will be removed.
In addition, update the documents referring `build_config.rb` which is
no longer used. The new `build_config.rb` describes the new configuration
structure in the comment.
`MRB_TRY()` does not work when compiled by C compiler with `cxx_exception`,
due to the mixture of `setjmp()` used by `mirb.c` and `throw` used by
the core. The original intension of e2e6554b56 is to protect code from
signal interruption, but the signal interruption is not well-defined in
mruby anyway.