Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions ext/rubydex/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ static VALUE cKeywordParameter;
// Interned once in `rdxi_initialize_graph` to avoid repeated symbol-table lookups on hot completion paths.
static ID id_self_receiver;

// Extracts the optional `self_receiver:` kwarg from `opts`. Returns NULL when the kwarg is
// absent or nil; raises ArgumentError when the value is the wrong type or empty.
// Extracts the required `self_receiver:` kwarg from `opts`. Returns NULL when the value is `nil`,
// which means "no self-type to walk" (e.g., empty class body where the singleton class hasn't
// been created). Raises ArgumentError if the kwarg is absent, of the wrong type, or an empty
// string. The kwarg is required so that callers commit to a self type — there is no implicit
// default.
static const char *extract_self_receiver(VALUE opts) {
if (NIL_P(opts)) {
return NULL;
rb_raise(rb_eArgError, "missing keyword: self_receiver");
}

VALUE kwarg_val;
rb_get_kwargs(opts, &id_self_receiver, 0, 1, &kwarg_val);
rb_get_kwargs(opts, &id_self_receiver, 1, 0, &kwarg_val);

if (kwarg_val == Qundef || NIL_P(kwarg_val)) {
if (NIL_P(kwarg_val)) {
return NULL;
}

Expand Down Expand Up @@ -608,11 +611,10 @@ static VALUE completion_result_to_ruby_array(struct CompletionResult result, VAL
return ruby_array;
}

// Graph#complete_expression: (Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword]
// Graph#complete_expression: (Array[String] nesting, self_receiver:) -> Array[Declaration | Keyword]
// Returns completion candidates for an expression context.
// The nesting array represents the lexical scope stack. The optional self_receiver keyword argument
// overrides the self-type (e.g., "Foo::<Foo>" for `def Foo.bar`); when nil, self is derived from
// the innermost nesting element.
// The nesting array represents the lexical scope stack. The required self_receiver keyword argument overrides the
// self-type (e.g., "Foo::<Foo>" for `def Foo.bar`); when nil, self is derived from the innermost nesting element.
static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
VALUE nesting, opts;
rb_scan_args(argc, argv, "1:", &nesting, &opts);
Expand All @@ -633,10 +635,11 @@ static VALUE rdxr_graph_complete_expression(int argc, VALUE *argv, VALUE self) {
return completion_result_to_ruby_array(result, self);
}

// Graph#complete_namespace_access: (String name, self_receiver: nil) -> Array[Declaration]
// Graph#complete_namespace_access: (String name, self_receiver:) -> Array[Declaration]
// Returns completion candidates after a namespace access operator (e.g., `Foo::`).
// The optional self_receiver kwarg is the caller's runtime self type, used to filter
// visibility-restricted singleton methods (e.g., `private_class_method`).
// The required self_receiver kwarg is the caller's runtime self type, used to filter
// visibility-restricted singleton methods (e.g., `private_class_method`). Pass `nil` when there
// is no caller context.
static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE self) {
VALUE name, opts;
rb_scan_args(argc, argv, "1:", &name, &opts);
Expand All @@ -652,10 +655,10 @@ static VALUE rdxr_graph_complete_namespace_access(int argc, VALUE *argv, VALUE s
return completion_result_to_ruby_array(result, self);
}

// Graph#complete_method_call: (String name, self_receiver: nil) -> Array[Declaration]
// Graph#complete_method_call: (String name, self_receiver:) -> Array[Declaration]
// Returns completion candidates after a method call operator (e.g., `foo.`).
// The optional self_receiver kwarg is the caller's runtime self type, used for MRI-style
// visibility checks (private/protected).
// The required self_receiver kwarg is the caller's runtime self type, used for visibility checks (private/protected).
// Pass `nil` when there is no caller context.
static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self) {
VALUE name, opts;
rb_scan_args(argc, argv, "1:", &name, &opts);
Expand All @@ -671,9 +674,9 @@ static VALUE rdxr_graph_complete_method_call(int argc, VALUE *argv, VALUE self)
return completion_result_to_ruby_array(result, self);
}

// Graph#complete_method_argument: (String name, Array[String] nesting, self_receiver: nil) -> Array[Declaration | Keyword | KeywordParameter]
// Graph#complete_method_argument: (String name, Array[String] nesting, self_receiver:) -> Array[Declaration | Keyword | KeywordParameter]
// Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`).
// See complete_expression for semantics of self_receiver.
// See complete_expression for semantics of self_receiver (required, may be nil).
static VALUE rdxr_graph_complete_method_argument(int argc, VALUE *argv, VALUE self) {
VALUE name, nesting, opts;
rb_scan_args(argc, argv, "2:", &name, &nesting, &opts);
Expand Down
22 changes: 11 additions & 11 deletions rbi/rubydex.rbi
Original file line number Diff line number Diff line change
Expand Up @@ -344,56 +344,56 @@ class Rubydex::Graph
# Returns completion candidates for an expression context. This includes all keywords, constants, methods, instance
# variables, class variables and global variables reachable from the current lexical scope and self type.
#
# The nesting array represents the lexical scope stack. The optional `self_receiver` keyword argument overrides the
# The nesting array represents the lexical scope stack. The required `self_receiver` keyword argument overrides the
# self type independently of the lexical scope (e.g., `"Foo::<Foo>"` for `def Foo.bar`). This distinction is important
# because constants and class variables are always attached to the lexical scope. Meanwhile, methods and instance
# variables are attached to the type of `self` and those don't always match.
# variables are attached to the type of `self` and those don't always match. Pass `nil` when the self type is unknown
sig do
params(
nesting: T::Array[String],
self_receiver: T.nilable(String),
).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword)])
end
def complete_expression(nesting, self_receiver: nil); end
def complete_expression(nesting, self_receiver:); end

# Returns completion candidates after a namespace access operator (e.g., `Foo::`). This includes all constants and
# singleton methods for the namespace and its ancestors.
#
# The optional `self_receiver` kwarg is the caller's runtime self type. It's used to filter visibility-restricted
# singleton methods (e.g., `private_class_method`). Pass `nil` (the default) for top-level/script scope.
# The required `self_receiver` kwarg is the caller's runtime self type. It's used to filter visibility-restricted
# singleton methods (e.g., `private_class_method`). Pass `nil` for top-level/script scope.
sig do
params(
name: String,
self_receiver: T.nilable(String),
).returns(T::Array[Rubydex::Declaration])
end
def complete_namespace_access(name, self_receiver: nil); end
def complete_namespace_access(name, self_receiver:); end

# Returns completion candidates after a method call operator (e.g., `foo.`). This includes all methods that exist on
# the type of the receiver and its ancestors.
#
# The optional `self_receiver` kwarg is the caller's runtime self type. It's used for visibility checks for `private`
# and `protected` methods. Pass `nil` (the default) for top-level/script scope.
# The required `self_receiver` kwarg is the caller's runtime self type. It's used for visibility checks for `private`
# and `protected` methods. Pass `nil` for top-level/script scope.
sig do
params(
name: String,
self_receiver: T.nilable(String),
).returns(T::Array[Rubydex::Method])
end
def complete_method_call(name, self_receiver: nil); end
def complete_method_call(name, self_receiver:); end

# Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`). This includes everything
# that expression completion provides plus keyword argument names of the method being called.
#
# See `complete_expression` for the semantics of `nesting` and `self_receiver`.
# See `complete_expression` for the semantics of `nesting` and `self_receiver` (required, may be `nil`).
sig do
params(
name: String,
nesting: T::Array[String],
self_receiver: T.nilable(String),
).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword, Rubydex::KeywordParameter)])
end
def complete_method_argument(name, nesting, self_receiver: nil); end
def complete_method_argument(name, nesting, self_receiver:); end

private

Expand Down
4 changes: 1 addition & 3 deletions rust/rubydex-sys/src/graph_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,9 +801,7 @@ fn run_and_finalize_completion(
///
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
/// - `nesting` must point to `nesting_count` valid, null-terminated UTF-8 strings.
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
/// overrides the self-type (e.g., `"Foo::<Foo>"` for completion inside `def Foo.bar`), while
/// the lexical nesting still comes from `nesting`.
/// - `self_receiver` is the fully qualified name of the **type of `self`**
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rdx_graph_complete_expression(
pointer: GraphPointer,
Expand Down
Loading
Loading