nvim-treesitter / nvim-treesitter/nvim-treesitter

[Vue] Fold: unexpected behavior in SFC

Open
#7,459 4 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Tree-sitter Query
Stars
14.4k
Forks
1.4k
Avg merge
4h 35m
Merged PRs (30d)
13

Description

Describe the bug

Treesitter's foldexpr() doesn't work as expected on entering a buffer of a Vue's SFC

Folds are OK only in <template> tag. In <script> and <style> tags there is only one fold on the tag itself. It can be "fixed" by either deleting the tag and applying "undo" operation, or creating the tag. So, I assume, the problem is in the initial parsing.

https://github.com/user-attachments/assets/b8009a8f-2fce-490d-8c76-4917397444bb

To Reproduce

Minimal config for reproduction. Tested both on stable and nightly releases

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
local uv = vim.uv or vim.loop

if not uv.fs_stat(lazypath) then
	local lazyrepo = "https://github.com/folke/lazy.nvim.git"
	local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
	if vim.v.shell_error ~= 0 then
		vim.api.nvim_echo({
			{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
			{ out, "WarningMsg" },
			{ "\nPress any key to exit..." },
		}, true, {})
		vim.fn.getchar()
		os.exit(1)
	end
end

vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
	spec = {
		{
			"nvim-treesitter/nvim-treesitter",
			event = { "BufReadPre", "BufNewFile" },
			build = ":TSUpdate",
			init = function()
				vim.wo.foldlevel = 99
				vim.wo.foldmethod = "expr"
				vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()"
			end,
			config = function()
				local treesitter = require("nvim-treesitter.configs")

				---@diagnostic disable-next-line: missing-fields
				treesitter.setup({
					highlight = {
						enable = true,
					},
					ensure_installed = {
						"javascript",
						"typescript",
						"html",
						"vue",
					},
				})
			end,
		},
	},
})

Sample Vue SFC

<template>
  <div class="first">
    <div class="second">
      <div class="third"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";

import { Import1 } from "./import1";
import { Import2 } from "./import2";
import { Import3 } from "./import3";

const data = ref<Data>({
  field1: "sad",
});
</script>

<style lang="scss" scoped>
  .first {
    width: 12px;
    height: 12px;
  }
  .second {
    width: 12px;
    height: 12px;
  }
  .third {
    width: 12px;
    height: 12px;
  }
</style>
Expected behavior

All folds in <script> and <style> tags should be available after entering a buffer

Output of :checkhealth nvim-treesitter
nvim-treesitter: require("nvim-treesitter.health").check()

Installation ~
- OK `tree-sitter` found 0.24.4 (parser generator, only needed for :TSInstallFromGrammar)
- OK `node` found v20.11.0 (only needed for :TSInstallFromGrammar)
- OK `git` executable found.
- OK `cc` executable found. Selected from { vim.NIL, "cc", "gcc", "clang", "cl", "zig" }
  Version: Apple clang version 16.0.0 (clang-1600.0.26.4)
- OK Neovim was compiled with tree-sitter runtime ABI version 14 (required >=13). Parsers must be compatible with runtime ABI.

OS Info:
{
  machine = "arm64",
  release = "24.1.0",
  sysname = "Darwin",
  version = "Darwin Kernel Version 24.1.0: Thu Oct 10 21:03:15 PDT 2024; root:xnu-11215.41.3~2/RELEASE_ARM64_T6000"
} ~

Parser/Features         H L F I J
  - c                   ✓ ✓ ✓ ✓ ✓
  - css                 ✓ . ✓ ✓ ✓
  - html                ✓ ✓ ✓ ✓ ✓
  - javascript          ✓ ✓ ✓ ✓ ✓
  - lua                 ✓ ✓ ✓ ✓ ✓
  - markdown            ✓ . ✓ ✓ ✓
  - markdown_inline     ✓ . . . ✓
  - query               ✓ ✓ ✓ ✓ ✓
  - scss                ✓ . ✓ ✓ ✓
  - typescript          ✓ ✓ ✓ ✓ ✓
  - vim                 ✓ ✓ ✓ . ✓
  - vimdoc              ✓ . . . ✓
  - vue                 ✓ . ✓ ✓ ✓

  Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections
         +) multiple parsers found, only one will be used
         x) errors found in the query, try to run :TSUpdate {lang} ~
Output of nvim --version
NVIM v0.11.0-dev-1335+g3f1d09bc94
Build type: RelWithDebInfo
LuaJIT 2.1.1732813678
Run "nvim -V1 -v" for more info

NVIM v0.10.2
Build type: Release
LuaJIT 2.1.1732813678
Run "nvim -V1 -v" for more info
Additional context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal configuration and sample Vue SFC in the issue, then compare fold behavior on entering the buffer with the behavior after editing a tag. Investigate the folding and parsing path for the script and style sections; done means all expected folds are available immediately after entering the buffer.

Written by the indexing model from the issue text.

Assessment

Tech stack
neovim, scss, typescript
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.