Skip to content

Commit 0eb9ad3

Browse files
feat(tree-sitter)!: Remove dependency on nvim-treesitter (#707)
1 parent 050ed17 commit 0eb9ad3

File tree

14 files changed

+299
-161
lines changed

14 files changed

+299
-161
lines changed

.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ luac.out
2727

2828
# Shared objects (inc. Windows DLLs)
2929
*.dll
30-
*.so
31-
*.so.*
3230
*.dylib
3331

3432
# Executables

DOCS.md

-3
Original file line numberDiff line numberDiff line change
@@ -1676,12 +1676,9 @@ More optimized version would be to create a lua file that has only necessary plu
16761676
-- ~/.config/nvim/lua/partials/org_cron.lua
16771677

16781678
-- If you are using lazy.vim do this:
1679-
local treesitter = vim.fn.stdpath('data') .. '/lazy/nvim-treesitter'
16801679
local orgmode = vim.fn.stdpath('data') .. '/lazy/orgmode'
16811680
vim.opt.runtimepath:append(orgmode)
1682-
vim.opt.runtimepath:append(treesitter)
16831681
-- If you are using Packer or any other package manager that uses built-in package manager, do this:
1684-
vim.cmd('packadd nvim-treesitter')
16851682
vim.cmd('packadd orgmode')
16861683

16871684
-- Run the orgmode cron

README.md

+21-46
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
### Requirements
2121

2222
* Neovim 0.9.2 or later
23-
* [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter)
2423

2524
### Installation
2625

@@ -33,39 +32,31 @@ Use your favourite package manager:
3332
```lua
3433
{
3534
'nvim-orgmode/orgmode',
36-
dependencies = {
37-
{ 'nvim-treesitter/nvim-treesitter', lazy = true },
38-
},
3935
event = 'VeryLazy',
4036
config = function()
41-
-- Load treesitter grammar for org
42-
require('orgmode').setup_ts_grammar()
43-
44-
-- Setup treesitter
45-
require('nvim-treesitter.configs').setup({
46-
highlight = {
47-
enable = true,
48-
},
49-
ensure_installed = { 'org' },
50-
})
51-
5237
-- Setup orgmode
5338
require('orgmode').setup({
5439
org_agenda_files = '~/orgfiles/**/*',
5540
org_default_notes_file = '~/orgfiles/refile.org',
5641
})
42+
43+
-- NOTE: If you are using nvim-treesitter with `ensure_installed = "all"` option
44+
-- add `org` to ignore_install
45+
-- require('nvim-treesitter.configs').setup({
46+
-- ensure_installed = 'all',
47+
-- ignore_install = { 'org' },
48+
-- })
5749
end,
5850
}
5951
```
6052

6153
</details>
6254

63-
<details open>
55+
<details>
6456
<summary><b><a href="https://github.com/wbthomason/packer.nvim">packer.nvim</a></b></summary>
6557
</br>
6658

6759
```lua
68-
use {'nvim-treesitter/nvim-treesitter'}
6960
use {'nvim-orgmode/orgmode', config = function()
7061
require('orgmode').setup{}
7162
end
@@ -79,7 +70,6 @@ end
7970
</br>
8071

8172
```vim
82-
Plug 'nvim-treesitter/nvim-treesitter'
8373
Plug 'nvim-orgmode/orgmode'
8474
```
8575

@@ -90,7 +80,6 @@ Plug 'nvim-orgmode/orgmode'
9080
</br>
9181

9282
```vim
93-
call dein#add('nvim-treesitter/nvim-treesitter')
9483
call dein#add('nvim-orgmode/orgmode')
9584
```
9685

@@ -104,29 +93,27 @@ since instructions above covers full setup
10493
```lua
10594
-- init.lua
10695

107-
-- Load custom treesitter grammar for org filetype
108-
require('orgmode').setup_ts_grammar()
109-
110-
-- Treesitter configuration
111-
require('nvim-treesitter.configs').setup {
112-
highlight = {
113-
enable = true,
114-
},
115-
ensure_installed = {'org'}, -- Or run :TSUpdate org
116-
}
117-
11896
require('orgmode').setup({
11997
org_agenda_files = {'~/Dropbox/org/*', '~/my-orgs/**/*'},
12098
org_default_notes_file = '~/Dropbox/org/refile.org',
12199
})
122-
```
100+
101+
-- NOTE: If you are using nvim-treesitter with `ensure_installed = "all"` option
102+
-- add `org` to ignore_install
103+
-- require('nvim-treesitter.configs').setup({
104+
-- ensure_installed = 'all',
105+
-- ignore_install = { 'org' },
106+
-- })
123107

124108
Or if you are using `init.vim`, wrap the above snippet like so:
125109
```vim
126110
" init.vim
127111
lua << EOF
128112

129-
require('orgmode').setup_ts_grammar() ...
113+
require('orgmode').setup({
114+
org_agenda_files = {'~/Dropbox/org/*', '~/my-orgs/**/*'},
115+
org_default_notes_file = '~/Dropbox/org/refile.org',
116+
})
130117

131118
EOF
132119
```
@@ -191,29 +178,17 @@ or a hands-on [tutorial](https://github.com/nvim-orgmode/orgmode/wiki/Getting-St
191178

192179
## Treesitter Info
193180
The built-in treesitter parser is used for parsing the org files.
194-
Highlights are experimental and partially supported.
195-
196-
### Advantages of treesitter over built in parsing/syntax:
197-
* More reliable, since parsing is done with a proper parsing tool
198-
* Better highlighting (Experimental, still requires improvements)
199-
* Future features will be easier to implement because the grammar already parses some things that were not parsed before (tables, latex, etc.)
200-
* Allows for easier hacking (custom motions that can work with TS nodes, etc.)
201181

202182
### Known highlighting issues and limitations
203183
* LaTex is still highlighted through syntax file
204184

205-
### Improvements over Vim's syntax highlighting
206-
* Better highlighting of certain parts (tags, deadline/schedule/closed dates)
207-
* [Treesitter highlight injections](https://github.com/nvim-treesitter/nvim-treesitter/blob/4f2265632becabcd2c5b1791fa31ef278f1e496c/CONTRIBUTING.md#injections) through `#BEGIN_SRC filetype` blocks
208-
* Headline markup highlighting (https://github.com/nvim-orgmode/orgmode/issues/67)
209-
210185
## Troubleshoot
211186
### Indentation is not working
212187
Make sure you are not overriding indentexpr in Org buffers with [nvim-treesitter indentation](https://github.com/nvim-treesitter/nvim-treesitter#indentation)
213188

214189
### I get `treesitter/query.lua` errors when opening agenda/capture prompt or org files
215-
Make sure you are using latest changes from [tree-sitter-org](https://github.com/milisims/tree-sitter-org) grammar.<br />
216-
by running `:TSUpdate org` and restarting the editor.
190+
Tree-sitter parser might not be installed.
191+
Try running `:lua require('orgmode.config'):reinstall_grammar()` to reinstall it.
217192

218193
### Dates are not in English
219194
Dates are generated with Lua native date support, and it reads your current locale when creating them.<br />

ftplugin/org.lua

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ local utils = require('orgmode.utils')
99

1010
vim.b.org_bufnr = vim.api.nvim_get_current_buf()
1111

12+
vim.treesitter.start()
13+
1214
config:setup_mappings('org', vim.b.org_bufnr)
1315
config:setup_mappings('text_objects', vim.b.org_bufnr)
1416
config:setup_foldlevel()
@@ -21,7 +23,7 @@ require('orgmode.org.indent').setup_virtual_indent()
2123
vim.bo.modeline = false
2224
vim.opt_local.fillchars:append('fold: ')
2325
vim.opt_local.foldmethod = 'expr'
24-
vim.opt_local.foldexpr = 'nvim_treesitter#foldexpr()'
26+
vim.opt_local.foldexpr = 'v:lua.require("orgmode.org.fold").foldexpr()'
2527
if utils.has_version_10() then
2628
vim.opt_local.foldtext = ''
2729
else

lua/orgmode/config/init.lua

+13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ function Config:__index(key)
2828
return rawget(getmetatable(self), key)
2929
end
3030

31+
function Config:install_grammar()
32+
local ok = pcall(vim.treesitter.language.add, 'org')
33+
if ok then
34+
return
35+
end
36+
require('orgmode.utils.treesitter.install').run()
37+
end
38+
39+
---@param url? string
40+
function Config:reinstall_grammar(url)
41+
return require('orgmode.utils.treesitter.install').run(url)
42+
end
43+
3144
---@param opts table
3245
---@return OrgConfig
3346
function Config:extend(opts)

lua/orgmode/init.lua

+5-41
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
_G.orgmode = _G.orgmode or {}
2-
local ts_revision = 'f8c6b1e72f82f17e41004e04e15f62a83ecc27b0'
3-
local setup_ts_grammar_used = false
42
---@type Org | nil
53
local instance = nil
64

@@ -98,52 +96,18 @@ function Org:setup_autocmds()
9896
})
9997
end
10098

101-
--- @param revision string?
102-
function Org.setup_ts_grammar(revision)
103-
setup_ts_grammar_used = true
104-
local parser_config = require('nvim-treesitter.parsers').get_parser_configs()
105-
---@diagnostic disable-next-line: inject-field
106-
parser_config.org = {
107-
install_info = {
108-
url = 'https://github.com/nvim-orgmode/tree-sitter-org',
109-
revision = revision or ts_revision,
110-
files = { 'src/parser.c', 'src/scanner.c' },
111-
},
112-
filetype = 'org',
113-
}
114-
end
115-
116-
---@private
117-
function Org._check_ts_grammar()
118-
vim.defer_fn(function()
119-
if setup_ts_grammar_used then
120-
return
121-
end
122-
local parser_config = require('nvim-treesitter.parsers').get_parser_configs()
123-
if parser_config and parser_config.org and parser_config.org.install_info.revision then
124-
if parser_config.org.install_info.revision ~= ts_revision then
125-
require('orgmode.utils').echo_error({
126-
'You are using outdated version of tree-sitter grammar for Orgmode.',
127-
'To use latest version, replace current grammar installation with "require(\'orgmode\').setup_ts_grammar()" and run :TSUpdate org.',
128-
'More info in setup section of readme: https://github.com/nvim-orgmode/orgmode#setup',
129-
})
130-
end
131-
else
132-
require('orgmode.utils').echo_error({
133-
'Cannot detect parser revision.',
134-
"Please check your org grammar's install info.",
135-
'Maybe you forgot to call "require(\'orgmode\').setup_ts_grammar()" before setup.',
136-
})
137-
end
138-
end, 200)
99+
function Org.setup_ts_grammar()
100+
require('orgmode.utils').echo_info(
101+
'calling require("orgmode").setup_ts_grammar() is no longer necessary. Dependency on nvim-treesitter was removed'
102+
)
139103
end
140104

141105
---@param opts? OrgDefaultConfig
142106
---@return Org
143107
function Org.setup(opts)
144108
opts = opts or {}
145-
Org._check_ts_grammar()
146109
local config = require('orgmode.config'):extend(opts)
110+
config:install_grammar()
147111
instance = Org:new()
148112
vim.defer_fn(function()
149113
if config.notifications.enabled and #vim.api.nvim_list_uis() > 0 then

lua/orgmode/org/fold.lua

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
-- Taken from https://github.com/nvim-treesitter/nvim-treesitter
2+
3+
local api = vim.api
4+
local ts_utils = require('orgmode.utils.treesitter')
5+
6+
---@type vim.treesitter.Query
7+
local query = nil
8+
9+
local M = {}
10+
11+
-- This is cached on buf tick to avoid computing that multiple times
12+
-- Especially not for every line in the file when `zx` is hit
13+
local folds_levels = ts_utils.memoize_by_buf_tick(function(bufnr)
14+
local max_fold_level = api.nvim_get_option_value('foldnestmax', { win = 0 })
15+
local trim_level = function(level)
16+
if level > max_fold_level then
17+
return max_fold_level
18+
end
19+
return level
20+
end
21+
22+
query = query or vim.treesitter.query.get('org', 'folds')
23+
local trees = vim.treesitter.get_parser(bufnr):parse()
24+
local root = trees[1]:root()
25+
26+
local matches = {}
27+
for _, node in query:iter_captures(root, bufnr) do
28+
table.insert(matches, node)
29+
end
30+
31+
---@type table<number, number>
32+
local start_counts = {}
33+
---@type table<number, number>
34+
local stop_counts = {}
35+
36+
local prev_start = -1
37+
local prev_stop = -1
38+
39+
local min_fold_lines = api.nvim_get_option_value('foldminlines', { win = 0 })
40+
41+
for _, match in ipairs(matches) do
42+
local start, _, stop, stop_col = match:range() ---@type integer, integer, integer, integer
43+
44+
if stop_col == 0 then
45+
stop = stop - 1
46+
end
47+
48+
local fold_length = stop - start + 1
49+
local should_fold = fold_length > min_fold_lines
50+
51+
-- Fold only multiline nodes that are not exactly the same as previously met folds
52+
-- Checking against just the previously found fold is sufficient if nodes
53+
-- are returned in preorder or postorder when traversing tree
54+
if should_fold and not (start == prev_start and stop == prev_stop) then
55+
start_counts[start] = (start_counts[start] or 0) + 1
56+
stop_counts[stop] = (stop_counts[stop] or 0) + 1
57+
prev_start = start
58+
prev_stop = stop
59+
end
60+
end
61+
62+
---@type string[]
63+
local levels = {}
64+
local current_level = 0
65+
66+
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
67+
for lnum = 0, api.nvim_buf_line_count(bufnr) do
68+
local prefix = ''
69+
70+
local last_trimmed_level = trim_level(current_level)
71+
current_level = current_level + (start_counts[lnum] or 0)
72+
local trimmed_level = trim_level(current_level)
73+
current_level = current_level - (stop_counts[lnum] or 0)
74+
local next_trimmed_level = trim_level(current_level)
75+
76+
-- Determine if it's the start/end of a fold
77+
-- NB: vim's fold-expr interface does not have a mechanism to indicate that
78+
-- two (or more) folds start at this line, so it cannot distinguish between
79+
-- ( \n ( \n )) \n (( \n ) \n )
80+
-- versus
81+
-- ( \n ( \n ) \n ( \n ) \n )
82+
-- If it did have such a mechanism, (trimmed_level - last_trimmed_level)
83+
-- would be the correct number of starts to pass on.
84+
if trimmed_level - last_trimmed_level > 0 then
85+
prefix = '>'
86+
elseif trimmed_level - next_trimmed_level > 0 then
87+
-- Ending marks tend to confuse vim more than it helps, particularly when
88+
-- the fold level changes by at least 2; we can uncomment this if
89+
-- vim's behavior gets fixed.
90+
-- prefix = "<"
91+
prefix = ''
92+
end
93+
94+
levels[lnum + 1] = prefix .. tostring(trimmed_level)
95+
end
96+
97+
return levels
98+
end)
99+
100+
---@return string
101+
function M.foldexpr()
102+
local buf = api.nvim_get_current_buf()
103+
local levels = folds_levels(buf) or {}
104+
105+
return levels[vim.v.lnum] or '0'
106+
end
107+
108+
return M

0 commit comments

Comments
 (0)