stimulus-lsp icon indicating copy to clipboard operation
stimulus-lsp copied to clipboard

Autocomplete for JavaScript

Open marcoroth opened this issue 2 years ago • 4 comments

The Stimulus LSP currently only supports completion for HTML and (HTML+ERB). There's also an opportunity to provide autocomplete for JavaScript files, especially within Stimulus controllers themselves.

For example, a controller like this should provide autocomplete for targets and all other Stimulus APIs:

import  { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["name"]
  
  connect() {
    this.|
         +----------------+
         | nameTarget     |
         | nameTargets    |
         | hasNameTarget  |
         +----------------+
  }
}

marcoroth avatar Oct 10 '23 20:10 marcoroth

🤔 It might be easier to build this as a TS-Server LSP plugin so it's gonna work with almost all editors out of the box (without building custom extensions on top)

Zeko369 avatar Oct 11 '23 08:10 Zeko369

Good point @Zeko369. I honestly haven't really dug deep into how we could properly implement that.

Any chance you know of an example doing this already?

marcoroth avatar Oct 11 '23 12:10 marcoroth

My initial thinking here is to leverage codelens together with code actions to make this capability a reality but the TS-Server LSP plugin is likely a far more fluid route opposed to employing custom logic (though I am yet to explore the available API and implementation requirements).

The capability needs to cater to both TS and JS projects, JS projects will be an easier undertaking but I see TS projects being a tad extraneous. I know for my use cases, I rely heavily on JSDoc annotations to describe static defined targets, values and classes and I'd be concerned that underlying declarations applied via TS-Server could conflict or complicate things.

For example, take the below sample wherein I've annotated nameTarget:

import  { Controller } from "@hotwired/stimulus"

export default class extends Controller {

  static targets = ["name"]
  
  connect() { 
    this.nameTarget 
  }
  
  /**
   * This annotation describing this target
   */
   nameTarget: HTMLElement;
}

The base reference of nameTarget is the only annotation which one would realistically require. The nameTargets[] and hasNameTarget do not necessarily need annotation reference because it is assumptive, but this is where considerations need to be had and maybe it could look something like this:

  1. Check for the presence/existence of typed occurrences
  2. When occurrences exist, inherit them
  3. Determine which static definitions are un-typed and apply

JSDoc Annotations may also be able to play a bigger role overall, specifically in the markup completions. Though some additional thought needs to be had on that front.

panoply avatar Oct 19 '23 19:10 panoply

Yeah, I'm all-in on supporting multiple scenarios. I think that the parser can/should detect what kind of approach the project, or even a single controller file is using, either by looking at the AST or by looking at whatever packages are included in the package.json.

There is also the stimulus-decorators approach for TypeScript projects, which we opened an issue for in stimulus-parser: https://github.com/marcoroth/stimulus-parser/issues/10.

I think as long as the stimulus-parser is capable enough for supporting multiple approaches, we could unify it into a common ControllerDefinition object, which Stimulus LSP then can rely on, without having to know anything about the implementation/parsing details.

marcoroth avatar Oct 19 '23 21:10 marcoroth