ember-tooling / tree-sitter-glimmer

A TreeSitter grammar for Glimmer (HBS) templates
https://ember-tooling.github.io/tree-sitter-glimmer/
24 stars 3 forks source link

Indent module support #60

Closed yads closed 5 months ago

yads commented 2 years ago

It looks like the indent module for this parser is disabled. What would be required to get it working? Right now indentation is totally broken in my hbs templates. This is my treesitter config:

require'nvim-treesitter.configs'.setup {
  ensure_installed = "maintained",
  matchup = {
    enable = true,
  },
  indent = {
    enable = true,
  },
  highlight = {
    enable = true, 
    additional_vim_regex_highlight = {
      "handlebars"
    },
  },
}

I do have 'mustache/vim-mustache-handlebars' installed, but it doesn't seem to help with the indentation at all. Currently I've set up prettier to auto format hbs files on save, but prettier is very opinionated on how to format handlebars files, so I would rather use something that has a lighter touch.

tlindsay commented 2 years ago

I would also like to see this land

alexlafroscia commented 2 years ago

This isn't something I will be working on myself, unfortunately; my OSS time is severely limited these days, and I am no longer actively using Ember or NeoVim. My workflow for Handlebars files in the last few years has been to lean into Prettier, even if it's not always ideal in the way it chooses to format things.

I'd be happy to review a PR that adds support for indentation, as long as it included tests to ensure that it isn't broken by changes down the road!

yads commented 2 years ago

Would it be worth transferring it to the glimmerjs org? I know I don't really have any experience with tree-sitter or C development.

NullVoxPopuli commented 10 months ago

I just ran in to the need for this!

yads commented 10 months ago

So there's this PR https://github.com/alexlafroscia/tree-sitter-glimmer/pull/112 but you can use my fork in the meantime. I'm not sure when it will be merged.

NullVoxPopuli commented 10 months ago

I just tried out the upstream indent module support, and there is an off by one (indent level) error it seems. in gjs/gts when I go to a new line, I'm always one indent level left of where I actually want my cursor to be.

Start:

  <div></div>

What happens:

  <div>
|</div>

What I expect:

  <div>
    |
  </div>

in normal hbs indents seem to work as expected, except that hitting enter does not do what I expect. Start: <div></div>

What happens:

<div>
|<div>

where, I would expect

<div>
  |
</div>

it seems the behavhior in hbs is actually the same as gjs/gts, but I was through off by the starting-indentation of my elements, and my very few remaining hbs files have no indentation at all typically.

it just depends on where your cursor starts... which needs fixing!

is there anything we can do about this from a treesitter perspective?

yads commented 10 months ago

I don't think this has anything to do with treesitter. Try disabling the indent module and you'll get the same behaviour. I think the behaviour you're seeing in html files is likely from https://github.com/windwp/nvim-autopairs or a similar plugin

yads commented 10 months ago

If you are using the nvim-autopairs plugin, you can add this rule to your configuration to get the same behaviour

      Rule(
        ">[%w%s]*$",
        "^%s*</",
        'handlebars'
      ):only_cr():use_regex(true)

Got it from https://github.com/windwp/nvim-autopairs/blob/master/lua/nvim-autopairs/rules/basic.lua#L63

NullVoxPopuli commented 10 months ago

I don't have autopairs working in gjs :sweat_smile:

how does that rule get set tho? that syntax looks goofy/unfamiliar

NullVoxPopuli commented 10 months ago

Here is a video of the behavior I'm seeingn:

Screencast from 2023-11-10 15-45-30.webm

yads commented 10 months ago

That was not the behaviour I was seeing. I was seeing what you had in Normal mode I guess. This is my autopairs configuration for glimmer

local npairs = require('nvim-autopairs')
    npairs.setup({
      check_ts = true,
    })
    local Rule = require('nvim-autopairs.rule')
    local cond = require('nvim-autopairs.conds')
    local ts_cond = require('nvim-autopairs.ts-conds')

    -- glimmer autopairs
    npairs.add_rules({
      Rule('{{#if.*}}', '{{/if}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#unless.*}}', '{{/unless}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#each-in.*}}', '{{/each-in}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#each.*}}', '{{/each}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#let.*}}', '{{/let}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#in-element.*}}', '{{/in-element}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('{{#link-to.*}}', '{{/link-to}}', 'handlebars'):use_regex(true):end_wise(cond.is_end_line()),
      Rule('|', '|', 'handlebars'):with_move(cond.done()):with_pair(ts_cond.is_ts_node({'block_params', 'block_statement_start'})),
      -- ensure nice behaviour when pressing CR inside an html tag
      Rule('>[%w%s]*$', '^%s*</', 'handlebars'):only_cr():use_regex(true)
    })
NullVoxPopuli commented 10 months ago

is there any way to get this behavior built in? rather than in each of our configs? but also, I feel like these control flow things would be better as lua-snip snippets?

but also, how do we fix the tag/element behavior?

yads commented 10 months ago

I'm not really sure what to tell you. There's likely something in your config that's causing this issue. Like I said before I added the config above I was not experiencing the problem you had. Try disabling the indent module and confirm if this is actually being caused by treesitter indent.

On Fri, Nov 10, 2023, 9:10 PM NullVoxPopuli @.***> wrote:

is there any way to get this behavior built in? rather than in each of our configs?

— Reply to this email directly, view it on GitHub https://github.com/alexlafroscia/tree-sitter-glimmer/issues/60#issuecomment-1806668516, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEAYZYSRIWQFVTISD3RYTTYD33BZAVCNFSM5MIPME7KU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBQGY3DMOBVGE3A . You are receiving this because you authored the thread.Message ID: @.***>

NullVoxPopuli commented 9 months ago

My lua intent behavior is flawless. For debugging purporeses, can you do a tiny screencast of your behaviors? (in gjs? and hbs?)

yads commented 9 months ago

Ok the first clip is with the autopairs rule I posted above and the second is without it. I have no idea with a gjs is.

https://github.com/alexlafroscia/tree-sitter-glimmer/assets/527463/7af9fb4a-3298-4585-ae4e-dde4463e6f28

https://github.com/alexlafroscia/tree-sitter-glimmer/assets/527463/77dff645-8012-43d7-bde0-338d7084f39c

NullVoxPopuli commented 9 months ago

Gjs is ember's new file format.

Made a whole tutorial: https://tutorial.glimdown.com

Can try it out as early as 3.28 with ember-template-imports

yads commented 9 months ago

Thanks for linking that. I suspect you're having issues with gjs and not hbs? I tried out gjs and indentation is indeed "broken" in gjs. Part of it is because glimmer_template, glimmer_opening_tag and glimmer_closing_tag are javascript nodes and not glimmer nodes. So the glimmer indent queries won't work for it. I played around with adding them to the javascript indents, but I can't get it to work. I suspect the reason is that the injected glimmer doesn't play nicely with the indents. I.e. all the indentation gets reset so all indentation is 1 off from where you want it to be in the following

<template>
  <div></div>
</template>

treesitter thinks the indentation for the div above is actually 0. So that's why you're seeing the closing div tag go back 1 indentation level when you press Enter. The way it works with jsx is that jsx is part of the javascript parser, rather than an injected language. Perhaps that should be the approach for gjs files as well?

NullVoxPopuli commented 9 months ago

Thanks for linking that. I suspect you're having issues with gjs and not hbs?

correct.

nodes and not glimmer nodes.

Maybe I defined the injection incorrectly. It's here: https://github.com/tree-sitter/tree-sitter-javascript/blob/master/queries/injections.scm#L32

Perhaps that should be the approach for gjs files as well?

since we have to change tree-sitter-javascript for that, it's unlikely to happen, unless we formally propose content-tag to tc39 https://wycats.github.io/polaris-sketchwork/content-tag.html

NullVoxPopuli commented 7 months ago

anyone know how to test this stuff, in my local env, it feels like all local changes aren't detected or break everything.

autopairs

this breaks TypeScript

yads commented 7 months ago

I used to use treesitter-playground, but I guess you have:

:Inspect to show the highlight groups under the cursor :InspectTree to show the parsed syntax tree ("TSPlayground") :EditQuery to open the Live Query Editor (Nvim 0.10+)

NullVoxPopuli commented 7 months ago

right, but how do you actually preview that your highlight addition works?

editing queries only selects things in the TSPlayground

NullVoxPopuli commented 5 months ago

This has landed!