Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workspace symbols #674

Merged
merged 10 commits into from
Apr 17, 2024
Merged

Workspace symbols #674

merged 10 commits into from
Apr 17, 2024

Conversation

scohen
Copy link
Collaborator

@scohen scohen commented Apr 1, 2024

Workspace symbols support. Workspace symbols finds all things that match a query in a project.

@scohen
Copy link
Collaborator Author

scohen commented Apr 1, 2024

It's worth noting that this isn't a feature I ever use, so I might be way off the mark here. Here are the current limitations:

  • It only searches for definitions of things, not references. I found that if I included everything, the search results were terrible and very repetitive. I feel that if you want to find references for something, you can do a workspace symbols request, then find references.
  • It only searches for things that belong to one of your project's apps, ignoring your dependencies. Again, finding things in dependencies made the results feel a lot less relevant than searching only your project.
  • We don't return any results if the query is less than 3 characters.

I'm not wedded to these limitations, and I'd like to hear from someone who uses these features.

@scohen scohen force-pushed the workspace-symbols branch from 80537e6 to 0b78f7e Compare April 1, 2024 20:49
@dimitarvp
Copy link
Contributor

Opening a file / workspace is fine, but the moment I click with the mouse anywhere in the viewport (using LunarVim i.e. Neovim + premade config) I get the following:

Screenshot 2024-04-02 at 10 25 16

Clicking left and right yields the same message, only the ID is increasing. No idea how to troubleshoot further.

Though it also has to be said that my Elixir files are now opening both with elixirls and lexical and I couldn't force my editor to only use lexical yet.

@dimitarvp
Copy link
Contributor

OK, some more screwing around reveals that this is kinda related to opening Neovim in a vertical split mode, I guess?

So I start my editor this way: lvim -O2 lib/file1.ex lib/file2.ex

I start off in file1.ex, I click on file2.ex, then I click back on file1.ex's viewport and the error shows up.

Same happens with -o2.

The error does NOT manifest itself if the editor is opened with a single pane.

Finally, trying to invoke listing of file symbols shows this big error:

LSP[lexical]: Error NO_RESULT_CALLBACK_FOUND: {
  id = 7,
  jsonrpc = "2.0",
  result = { {
      children = { {
          children = {},
          kind = 12,
          name = "receive_srr(%Conn{} = conn, %{oem: _} = params)",
          range = {
            ["end"] = {
              character = 5,
              line = 39
            },
            start = {
              character = 2,
              line = 31
            }
          },
          selectionRange = {
            ["end"] = {
              character = 53,
              line = 31
            },
            start = {
              character = 6,
              line = 31
            }
          }
        }, {
          children = {},
          kind = 12,
          name = "receive_mo(%Conn{} = conn, %{oem: _} = params)",
          range = {
            ["end"] = {
              character = 5,
              line = 62
            },
            start = {
              character = 2,
              line = 54
            }
          },
          selectionRange = {
            ["end"] = {
              character = 52,
              line = 54
            },
            start = {
              character = 6,
              line = 54
            }
          }
        } },
      kind = 2,
      name = "OssM2m.V1.ShortMessages.SmsController",
      range = {
        ["end"] = {
          character = 3,
          line = 63
        },
        start = {
          character = 0,
          line = 0
        }
      },
      selectionRange = {
        ["end"] = {
          character = 47,
          line = 0
        },
        start = {
          character = 10,
          line = 0
        }
      }
    } }
}

Hope any of that helps.

@dimitarvp
Copy link
Contributor

Oh btw, this also happens not just when clicking the buffers with the mouse. Doing C-h and C-l causes the error as well.

@scohen
Copy link
Collaborator Author

scohen commented Apr 2, 2024

This looks to be a problem with the plugin, as evidenced by the fact that it seems to only manifest itself when something editor-specific is happening. The LSP has no idea what's going on with the editor. The response you sent looks like a valid document symbols response. I'm not a vim user, so maybe @scottming has ideas.

The ["end"] in selection range is suspicious though.

@dimitarvp
Copy link
Contributor

Sorry, which plugin?

I can make a super mini Elixir project and see if we can have that reproduced on your machine (if you use NeoVim at all, that is).

@scohen
Copy link
Collaborator Author

scohen commented Apr 2, 2024

whatever you're using to enable language servers with vim. Maybe "LSP client" is better terminology.
I did verify that the responses are correct responses; the "end" isn't in a list in the actual JSON.

@dimitarvp
Copy link
Contributor

Well I suppose it's NeoVim's builtin LSP software.

Any ideas how can I troubleshoot this further? I am busy enough and not being versed in the implementation details of my editor is a conscious choice that I am not looking to change, I am afraid.

Is there any other way I can help?

@scohen
Copy link
Collaborator Author

scohen commented Apr 2, 2024

One of our contributors, @scottming has been helpful with this stuff in the past.
What's interesting is that the response you've highlighted is from a document symbols response, not a workspace symbols response. This is probably why clicking around is crashing things, as those requests are fired whenever the cursor moves.

@scohen scohen force-pushed the workspace-symbols branch from acbc218 to 1e45238 Compare April 3, 2024 00:12
@scottming
Copy link
Collaborator

@scohen @dimitarvp I can replicate this error, will take a look today or tomorrow.

@dimitarvp
Copy link
Contributor

@scohen My apologies for not posting the output of listing workspace symbols. My bad. I'll do that and post the output Later™.

@scohen scohen force-pushed the workspace-symbols branch from 1e45238 to 4e74e7d Compare April 3, 2024 16:17
@scohen scohen marked this pull request as ready for review April 10, 2024 00:35
@scohen scohen force-pushed the workspace-symbols branch from 4e74e7d to 4fa75d0 Compare April 11, 2024 15:29
Copy link
Collaborator

@scottming scottming left a comment

Choose a reason for hiding this comment

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

CleanShot 2024-04-12 at 15 09 42@2xI tried out this branch and found that it works very well when searching for function definition symbols, but when I want to search for modules, it still first returns functions and the functions from dependencies. I think when the first letter is capitalized, it should prioritize returning modules, and it should prioritize returning the last module with a high degree of match.

Additionally, when I enter the attribute @user, it doesn't return anything. Is this intentional?

@scohen
Copy link
Collaborator Author

scohen commented Apr 12, 2024

but when I want to search for modules, it still first returns functions

That's not how workspace symbols works or is supposed to work. You're searching for all symbols, not a specific type, and if a symbol has some text in it, you're going to get that symbol back. We can control ordering to an extent though different editors sort things differently.

it still first returns functions and the functions from dependencies.

I've noticed this too, i don't know what reverted to cause this.

Additionally, when I enter the attribute @user, it doesn't return anything. Is this intentional?

I get module attributes when i search for their names (user in this case), but not when using the @ prefix. I'll investigate.

@scohen
Copy link
Collaborator Author

scohen commented Apr 12, 2024

@scottming I fixed the dependencies issue, I added nil to the app for testing, which pulled in anything that didn't have an app, which included a lot of dependencies. I removed nil from the application list, so you shouldn't see any deps in your completions any more.

As for the module attributes, I pulled out the leading @ sign when creating the subject to normalize them, so that's why they wouldn't appear as results if the query included a leading @. I'm not sure why i did that, it doesn't affect quality, so i removed that.

@scohen scohen force-pushed the workspace-symbols branch 4 times, most recently from 03e890d to efb2e2e Compare April 13, 2024 00:47
@scottming
Copy link
Collaborator

That's not how workspace symbols works or is supposed to work. You're searching for all symbols, not a specific type, and if a symbol has some text in it, you're going to get that symbol back. We can control ordering to an extent though different editors sort things differently.

So if I want to quickly search for a module using this feature, how should I do it, especially when I don't quite remember the context of the module(Like only remember the User, not LiveDemoAccounts)?

@scohen
Copy link
Collaborator Author

scohen commented Apr 14, 2024

So if I want to quickly search for a module using this feature, how should I do it, especially when I don't quite remember the context of the module(Like only remember the User, not LiveDemoAccounts

Searching for "User" should find it just fine.

@scottming
Copy link
Collaborator

Searching for "User" should find it just fine.

But as I commented before, there are some issues with the sorting when searching like this. I actually don't quite understand why the user_fixture function in the fixtures file would be ranked ahead of the User module.

CleanShot 2024-04-15 at 21 40 02@2x

@scottming
Copy link
Collaborator

BTW, aside from filtering out dependencies, it seems unnecessary for constants like @impl ... to appear in the results

CleanShot 2024-04-15 at 21 46 08@2x

@scohen
Copy link
Collaborator Author

scohen commented Apr 15, 2024

why the user_fixture function in the fixtures file would be ranked ahead of the User module.

Because your editor is ranking them that way, we merely provide symbols. It's also doing something annoying by implying that the path has something to do with the returned results.

That said, we do rank them higher because the term user comes earlier in the symbol.

I want to be very clear here, we are providing a list of workspace symbols that match a query. Your editor then takes this list and orders it the way it sees fit. You're disagreeing with that ranking; we don't have much control over it.

@scohen
Copy link
Collaborator Author

scohen commented Apr 15, 2024

BTW, aside from filtering out dependencies, it seems unnecessary for constants like @impl ... to appear in the results

That's your opinion. It's quite possible that someone wants to see where they use @impl or search for @impl GenServer.

@scottming
Copy link
Collaborator

I want to be very clear here, we are providing a list of workspace symbols that match a query. Your editor then takes this list and orders it the way it sees fit. You're disagreeing with that ranking; we don't have much control over it.

Actually, I double-checked and found that VSCode does indeed reorder, while nvim does not; it simply displays the data returned by lexical. When I search for Product, this is the specific response received by the client.

Response
[DEBUG][2024-04-17 10:15:48] .../vim/lsp/rpc.lua:387  "rpc.receive" {
  id = 32,
  jsonrpc = "2.0",
  result = { {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 35,
            line = 9
          },
          start = {
            character = 6,
            line = 9
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/test/support/fixtures/catalog_fixtures.ex"
      },
      name = "LiveDemo.CatalogFixtures.product_fixture/1"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 22,
            line = 37
          },
          start = {
            character = 6,
            line = 37
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.get_product!/1"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 49,
            line = 72
          },
          start = {
            character = 7,
            line = 72
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo_web/live/product_live/form_component.ex"
      },
      name = "LiveDemoWeb.ProductLive.FormComponent.save_product/3"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 50,
            line = 57
          },
          start = {
            character = 7,
            line = 57
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo_web/live/product_live/form_component.ex"
      },
      name = "LiveDemoWeb.ProductLive.FormComponent.save_product/3"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 19,
            line = 19
          },
          start = {
            character = 6,
            line = 19
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.list_products/0"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 49,
            line = 69
          },
          start = {
            character = 6,
            line = 69
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.update_product/2"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 34,
            line = 51
          },
          start = {
            character = 6,
            line = 51
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.create_product/1"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 42,
            line = 87
          },
          start = {
            character = 6,
            line = 87
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.delete_product/1"
    }, {
      kind = 12,
      location = {
        range = {
          ["end"] = {
            character = 56,
            line = 100
          },
          start = {
            character = 6,
            line = 100
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog.ex"
      },
      name = "LiveDemo.Catalog.change_product/2"
    }, {
      kind = 2,
      location = {
        range = {
          ["end"] = {
            character = 38,
            line = 0
          },
          start = {
            character = 10,
            line = 0
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo_web/live/product_live/show.ex"
      },
      name = "LiveDemoWeb.ProductLive.Show"
    }, {
      kind = 2,
      location = {
        range = {
          ["end"] = {
            character = 39,
            line = 0
          },
          start = {
            character = 10,
            line = 0
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo_web/live/product_live/index.ex"
      },
      name = "LiveDemoWeb.ProductLive.Index"
    }, {
      kind = 2,
      location = {
        range = {
          ["end"] = {
            character = 47,
            line = 0
          },
          start = {
            character = 10,
            line = 0
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo_web/live/product_live/form_component.ex"
      },
      name = "LiveDemoWeb.ProductLive.FormComponent"
    }, {
      kind = 2,
      location = {
        range = {
          ["end"] = {
            character = 34,
            line = 0
          },
          start = {
            character = 10,
            line = 0
          }
        },
        uri = "file:///Users/scottming/Code/live_demo/lib/live_demo/catalog/product.ex"
      },
      name = "LiveDemo.Catalog.Product"
    } }
}
Below is the display effect.
effect image
You can use these command to easily create a Phoenix project to replicate these issues.
mix phx.new live_demo
mix phx.gen.live Catalog Product products title:string description:string price:decimal views:integer

@scohen
Copy link
Collaborator Author

scohen commented Apr 17, 2024

I explained why the ordering is the way it is. I feel like we can go back and forth on this, but ordering is more a property of the fuzzy matcher while this pr is about enabling workspace symbols.
emacs also reorders for what it’s worth.

Copy link
Collaborator

@scottming scottming left a comment

Choose a reason for hiding this comment

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

Sorting issues may require more thought, but can be addressed in the future PR or client-side

scohen added 10 commits April 17, 2024 10:12
Wired up workspace symbols. Things work, but this needs some
_love_. The search is kind of slow, and results are not particularly
relevant. I also don't use this feature much, so I don't know if we're
supposed to find _everything_ or, say, definitions.

I'm putting this up here as a draft PR while I open another branch
that will work toward improving relevance and performance.
Made somewhat significant changes to the fuzzy matcher to improve
performance and relevance of the results.

I found that the matcher was returning a ton of results when it was
returning references to things, so I pared it down to only consider
definitions, which seems to improve the relevance of results a lot.

I also only had it return definitions in one of the current project's
applications, as searching your dependencies for a definition didn't
seem to be a common use case.

The fuzzy matcher also now considers the type of the entry being
indexed when it builds the subject. This gives us much nicer and more
relevant search results, and gives us the ability to tune them more
specifically in the future.
  * Re-added @ in module attributes
  * Removed entries with nil app names
@scohen scohen force-pushed the workspace-symbols branch from efb2e2e to bc30452 Compare April 17, 2024 17:12
@scohen scohen merged commit 084598f into main Apr 17, 2024
9 checks passed
@scohen scohen deleted the workspace-symbols branch April 17, 2024 20:23
@scohen scohen added this to the 0.6 Release milestone Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants