Skip to content

Conversation

@joeldrapper
Copy link
Contributor

Draft to fix #77

I need to verify there aren’t any unintended consequences of removing the outer class and module selectors.

@cla-bot cla-bot bot added the cla-signed label May 1, 2025
@joeldrapper
Copy link
Contributor Author

joeldrapper commented May 1, 2025

Okay, yeah, this is no good. Each method definition has a body statement so this basically outlines every line of code in the file. 🙈

@joeldrapper
Copy link
Contributor Author

joeldrapper commented May 1, 2025

I guess we could just add the original query back.

(call
    method: (identifier) @run (#any-of? @run "describe" "context" "test" "it")
    arguments: (argument_list . (_)+) @name
) @item

I think this would be compatible with the new changes. I don’t love that it will select these methods no matter where they appear in the tree. Like if I call context from inside a method.

At the moment, I’m struggling to even get the dev extension to build on main. Not sure what it is.

@joeldrapper joeldrapper force-pushed the fix-rspec-outlines branch from 6332c28 to a0209d4 Compare May 1, 2025 10:48
@joeldrapper
Copy link
Contributor Author

Okay, I’ve pushed up a change that I think will fix this issue, even though it’s much less precise. Ideally, there would be a way to select program and then any number of nested call blocks where the call message is one of describe, it, test, etc.

Anyway, I can’t test this locally at the moment because I can’t get Zed to install a dev extension even on main.

@joeldrapper
Copy link
Contributor Author

Ideally, there would be a way to select program and then any number of nested call blocks where the call message is one of describe, it, test, etc.

I guess we could manually do this for 3-4 levels of nesting. It’s unlikely many people will nest more than that. I just don’t think there’s a way to have an infinite repeating pattern unless I’m missing something.

)?
) @item
)
; Test methods
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the mentioned issue, but the query also captures one-line it blocks with empty contexts. For example, given this Ruby code:

describe 'content' do
      it { is_expected.to_not allow_value('').for(:content) }
      it { is_expected.to validate_length_of(:content).is_at_most(described_class::CONTENT_SIZE_LIMIT) }
    end

The outline will be:

CleanShot 2025-05-01 at 13 45 45@2x

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do something simple and just assert that @run is not it:

; Test methods
(call
    method: (identifier) @run @name (#any-of? @run "describe" "context" "test" "it")
    arguments: (argument_list . [
            (string) @name
            (simple_symbol) @name
            (scope_resolution) @name
            (constant) @name
            "," @context
        ]* [
            (string) @name
            (simple_symbol) @name
            (scope_resolution) @name
            (constant) @name
        ]
    )?
    (#not-eq? @run "it") ; <= Here
) @item

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this would match something like this

def foo
  bar.describe("test") do
    # ...
  end
end

Support up to 4 levels of describe/context/test/it nesting
@joeldrapper
Copy link
Contributor Author

I’ve updated this with 4 levels of nesting.

Screen.Recording.2025-05-01.at.19.12.23.-.01.mp4

@vitallium
Copy link
Collaborator

I’ve updated this with 4 levels of nesting.
Screen.Recording.2025-05-01.at.19.12.23.-.01.mp4

Thanks! It looks good, but I found some cases where the proposed outline queries don't capture certain it blocks.
You can check this file https://gitlab.com/gitlab-org/gitlab/-/blob/f10fce240ef7d7eeb8ae698c6bd077617681e90e/spec/helpers/operations_helper_spec.rb#L61

The it 'returns the correct values' do block doesn't show up in the outline view. We could probably revert to the original queries to resolve this issue and then work on finding a cleaner solution. WDYT, @joeldrapper?

@joeldrapper
Copy link
Contributor Author

I think that one is five levels deep, not 4. We'd have to add another level.

It's in describe/describe/context/context/context/it. I didn't think people would nest that far.

I can easily add another couple of levels. It will be slightly tricky to maintain since a lot of the query is duplicated.

@joeldrapper
Copy link
Contributor Author

Okay, here's another idea that would allow for infinite nesting. We select the first level from program, either going via RSpec or a nil receiver. Then we look for it/test/describe/context nested in a describe/context block, but we don't ensure that it's describe/context blocks all the way from program. This wouldn't be perfect but it's unlikely you'd trigger it from non-test code.

@joeldrapper
Copy link
Contributor Author

@vitallium I just updated the PR to use the technique I mentioned above. This seems to work with the file you linked. I also added shared_examples as one of the DSL methods.

@vitallium
Copy link
Collaborator

@vitallium I just updated the PR to use the technique I mentioned above. This seems to work with the file you linked. I also added shared_examples as one of the DSL methods.

Awesome, thank you!

@joeldrapper I have a small suggestion. I think we can rely on tree-sitter' query precedence here and add support for one-liners like it { is_expected.to be_valid } and its. Since TS applies queries in order and later queries can override or extend earlier matches, we can add the following pattern at the end of the query file to ensure these one-liners are captured as well:

;; Match one-liners like `it { is_expected.to be_valid }`
(call
  method: (identifier) @run (#eq? @run "it")
  block: (block (_) @name)
) @item

Thoughts?

@joeldrapper
Copy link
Contributor Author

I'm concerned this might capture too much to @name since (_) could be anything. I'll try it though.

@joeldrapper
Copy link
Contributor Author

joeldrapper commented May 3, 2025

I added a new query for one-line RSpec expectations.

Screenshot 2025-05-04 at 00 02 13

@joeldrapper joeldrapper marked this pull request as ready for review May 3, 2025 23:04
@vitallium
Copy link
Collaborator

@joeldrapper I think we can go ahead and land this. Thank you for working on it!

@vitallium vitallium merged commit 2d2b5dd into zed-extensions:main May 4, 2025
1 check passed
This was referenced May 4, 2025
notpeter pushed a commit to zed-industries/extensions that referenced this pull request May 6, 2025
Hi, this PR updates the Ruby extension to
[v0.6.0](https://github.com/zed-extensions/ruby/releases/tag/v0.6.0).

## What's changed

- Update Rust crate zed_extension_api to 0.5.0 by @renovate in
zed-extensions/ruby#44
- Fix RSpec outlines by @joeldrapper in
zed-extensions/ruby#78

Thanks!
lucascompython pushed a commit to lucascompython/extensions that referenced this pull request Oct 3, 2025
Hi, this PR updates the Ruby extension to
[v0.6.0](https://github.com/zed-extensions/ruby/releases/tag/v0.6.0).

## What's changed

- Update Rust crate zed_extension_api to 0.5.0 by @renovate in
zed-extensions/ruby#44
- Fix RSpec outlines by @joeldrapper in
zed-extensions/ruby#78

Thanks!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Outline panel no longer shows nested RSpec contexts/specs in v0.5.6

2 participants