Skip to content

Commit 95fd9b3

Browse files
feat: Add support for basic LSP (#1088)
1 parent eff6b77 commit 95fd9b3

10 files changed

Lines changed: 182 additions & 34 deletions

File tree

README.org

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ Use your favourite package manager. We recommend [[https://github.com/folke/lazy
3838
org_default_notes_file = '~/orgfiles/refile.org',
3939
})
4040

41-
-- NOTE: If you are using nvim-treesitter with ~ensure_installed = "all"~ option
42-
-- add ~org~ to ignore_install
43-
-- require('nvim-treesitter.configs').setup({
44-
-- ensure_installed = 'all',
45-
-- ignore_install = { 'org' },
46-
-- })
41+
-- Experimental LSP support
42+
vim.lsp.enable('org')
4743
end,
4844
}
4945
#+END_SRC

docs/configuration.org

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This page contains information about all configuration that can be provided to t
88
- [[#calendar-settings][Calendar settings]]
99
- [[#tags-settings][Tags settings]]
1010
- [[#mappings][Mappings]]
11+
- [[#lsp][Lsp]]
1112
- [[#features][Features]]
1213
- [[#user-interface][User interface]]
1314

@@ -2272,6 +2273,25 @@ supported: =*=, =_=, =/=, =+=, =~=, === These cannot be changed.
22722273
:END:
22732274
To make all mappings dot repeatable, install [[https://github.com/tpope/vim-repeat][vim-repeat]] plugin.
22742275

2276+
** Lsp
2277+
:PROPERTIES:
2278+
:CUSTOM_ID: lsp
2279+
:END:
2280+
📝 NOTE: Experimental
2281+
2282+
There is basic LSP support available in org files. Available methods:
2283+
- =textDocument/documentSymbol= - Shows list of headlines in current file, correctly nested
2284+
- =workspace/symbol= - List and filter all headlines that are part of [[#org_agenda_files][org_agenda_files]]
2285+
- =textDocument/completion= - Autocompletion results. More details in [[#autocompletion][autocompletion]].
2286+
NOTE: If you are using any [[file:./plugins.org::#completion-plugins][completion plugins]],
2287+
make sure to remove the custom source settings for orgmode. It's no longer needed.
2288+
IF you are using =omnifunc=, it's best to not set it to builtin LSP omnifunc (=v:lua.vim.lsp.omnifunc=) in orgmode files, due to some edge cases.
2289+
2290+
To enable the orgmode lsp, make sure to call =vim.lsp.enable=:
2291+
#+begin_src lua
2292+
vim.lsp.enable('org')
2293+
#+end_src
2294+
22752295
** Features
22762296
:PROPERTIES:
22772297
:CUSTOM_ID: features

docs/index.org

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ To view this documentation offline in Neovim, run =:Org help=. More info in [[#g
2323
org_agenda_files = '~/orgfiles/**/*',
2424
org_default_notes_file = '~/orgfiles/refile.org',
2525
})
26+
-- Experimental LSP support
27+
vim.lsp.enable('org')
2628
end,
2729
}
2830
#+end_src

docs/installation.org

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,24 @@ Here are few examples:
1515
org_agenda_files = '~/orgfiles/**/*',
1616
org_default_notes_file = '~/orgfiles/refile.org',
1717
})
18+
-- Experimental LSP support
19+
vim.lsp.enable('org')
1820
end,
1921
}
2022
#+end_src
21-
2. [[https://github.com/lewis6991/pckr.nvim][pckr.nvim]]
23+
2. vim.pack (Available only in Neovim 0.12+)
24+
#+begin_src lua
25+
vim.pack.add({
26+
{ src = 'https://github.com/nvim-orgmode/orgmode '}
27+
})
28+
require('orgmode').setup({
29+
org_agenda_files = '~/orgfiles/**/*',
30+
org_default_notes_file = '~/orgfiles/refile.org',
31+
})
32+
-- Experimental LSP support
33+
vim.lsp.enable('org')
34+
#+end_src
35+
3. [[https://github.com/lewis6991/pckr.nvim][pckr.nvim]]
2236
#+begin_src lua
2337
require('pckr').add({
2438
{
@@ -32,7 +46,7 @@ Here are few examples:
3246
}
3347
})
3448
#+end_src
35-
3. [[https://github.com/junegunn/vim-plug][vim-plug]]
49+
4. [[https://github.com/junegunn/vim-plug][vim-plug]]
3650
#+begin_src vim
3751
Plug 'nvim-orgmode/orgmode'
3852

@@ -43,7 +57,7 @@ Here are few examples:
4357
})
4458
EOF
4559
#+end_src
46-
4. [[https://github.com/Shougo/dein.vim][dein.vim]]
60+
5. [[https://github.com/Shougo/dein.vim][dein.vim]]
4761
#+begin_src vim
4862
call dein#add('nvim-orgmode/orgmode')
4963

docs/plugins.org

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Link: [[https://github.com/nvim-orgmode/telescope-orgmode.nvim][telescope-orgmod
5757
:PROPERTIES:
5858
:CUSTOM_ID: completion-plugins
5959
:END:
60+
61+
📝 NOTE: There is experimental LSP support that provides the autocompletion. See [[file:./configuration.org::*Lsp][Lsp section]] for more details.
62+
6063
*** blink.cmp
6164
:PROPERTIES:
6265
:CUSTOM_ID: blinkcmp
@@ -197,26 +200,10 @@ Example configuration with few of these plugins using [[https://github.com/folke
197200
org_default_notes_file = '~/orgfiles/refile.org',
198201
})
199202
require('org-bullets').setup()
200-
require('blink.cmp').setup({
201-
sources = {
202-
per_filetype = {
203-
org = {'orgmode'}
204-
},
205-
providers = {
206-
orgmode = {
207-
name = 'Orgmode',
208-
module = 'orgmode.org.autocompletion.blink',
209-
fallbacks = { 'buffer' },
210-
},
211-
},
212-
},
213-
})
203+
require('blink.cmp').setup({})
214204

215-
require('telescope').setup()
216-
require('telescope').load_extension('orgmode')
217-
vim.keymap.set('n', '<leader>r', require('telescope').extensions.orgmode.refile_heading)
218-
vim.keymap.set('n', '<leader>fh', require('telescope').extensions.orgmode.search_headings)
219-
vim.keymap.set('n', '<leader>li', require('telescope').extensions.orgmode.insert_link)
205+
-- Experimental LSP support
206+
vim.lsp.enable('org')
220207
end,
221208
}
222209
#+end_src

lsp/org.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---@type vim.lsp.Config
2+
return {
3+
cmd = require('orgmode.lsp.server'),
4+
filetypes = { 'org' },
5+
}

lua/orgmode/files/elements/range.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,11 @@ function Range:clone()
8383
})
8484
end
8585

86+
function Range:to_lsp()
87+
return {
88+
start = { line = self.start_line - 1, character = 0 },
89+
['end'] = { line = self.end_line, character = 0 },
90+
}
91+
end
92+
8693
return Range

lua/orgmode/lsp/handlers.lua

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
local methods = vim.lsp.protocol.Methods
2+
local OrgLspHandlers = {}
3+
4+
local HEADLINE_KIND = vim.lsp.protocol.SymbolKind.Struct
5+
6+
---@param headline OrgHeadline
7+
local function get_headline_symbol(headline)
8+
---@cast headline OrgHeadline
9+
local range = headline:get_range():to_lsp()
10+
local result = {
11+
name = headline:get_title(),
12+
kind = HEADLINE_KIND,
13+
range = range,
14+
selectionRange = range,
15+
}
16+
local child_headlines = headline:get_child_headlines()
17+
if #child_headlines > 0 then
18+
result.children = vim.tbl_map(get_headline_symbol, child_headlines)
19+
end
20+
return result
21+
end
22+
23+
OrgLspHandlers[methods.textDocument_documentSymbol] = function(params)
24+
local filename = vim.uri_to_fname(params.textDocument.uri)
25+
local orgfile = require('orgmode').files:load_file_sync(filename)
26+
if not orgfile then
27+
return {}
28+
end
29+
30+
return vim.tbl_map(get_headline_symbol, orgfile:get_top_level_headlines())
31+
end
32+
33+
OrgLspHandlers[methods.workspace_symbol] = function(params)
34+
local results = {}
35+
local headlines = require('orgmode').files:find_headlines_matching_search_term(params.query or '', false, false)
36+
for _, headline in pairs(headlines) do
37+
table.insert(results, {
38+
name = headline:get_title(),
39+
kind = HEADLINE_KIND,
40+
location = {
41+
uri = vim.uri_from_fname(headline.file.filename),
42+
range = headline:get_range():to_lsp(),
43+
},
44+
})
45+
end
46+
47+
return results
48+
end
49+
50+
OrgLspHandlers[methods.textDocument_completion] = function(params)
51+
local line = vim.api
52+
.nvim_buf_get_lines(vim.uri_to_bufnr(params.textDocument.uri), params.position.line, params.position.line + 1, false)[1]
53+
:sub(1, params.position.character)
54+
55+
local org = require('orgmode')
56+
local offset = org.completion:get_start({ line = line }) + 1
57+
local base = string.sub(line, offset)
58+
59+
local completion = org.completion:complete({
60+
line = line,
61+
base = base,
62+
fuzzy = true,
63+
})
64+
65+
local results = vim.tbl_map(function(item)
66+
return {
67+
label = item.word,
68+
labelDetails = item.menu and { description = item.menu } or nil,
69+
}
70+
end, completion)
71+
72+
return {
73+
isIncomplete = true,
74+
items = results,
75+
}
76+
end
77+
78+
return OrgLspHandlers

lua/orgmode/lsp/server.lua

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
local handlers = require('orgmode.lsp.handlers')
2+
3+
return function(dispatchers)
4+
local closing = false
5+
local srv = {}
6+
7+
function srv.request(method, params, callback)
8+
if method == 'initialize' then
9+
callback(nil, {
10+
capabilities = {
11+
documentSymbolProvider = true,
12+
workspaceSymbolProvider = true,
13+
completionProvider = {
14+
triggerCharacters = { '#', '+', ':', '*', '.', '/' },
15+
},
16+
},
17+
})
18+
elseif method == 'shutdown' then
19+
callback(nil, nil)
20+
elseif handlers[method] then
21+
vim.schedule(function()
22+
callback(nil, handlers[method](params))
23+
end)
24+
end
25+
return true, 1
26+
end
27+
28+
function srv.notify(method)
29+
if method == 'exit' then
30+
dispatchers.on_exit(0, 15)
31+
end
32+
end
33+
34+
function srv.is_closing()
35+
return closing
36+
end
37+
38+
function srv.terminate()
39+
closing = true
40+
end
41+
42+
return srv
43+
end

store.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ Use your favourite package manager. We recommend
3838
org_default_notes_file = '~/orgfiles/refile.org',
3939
})
4040

41-
-- NOTE: If you are using nvim-treesitter with ~ensure_installed = "all"~ option
42-
-- add ~org~ to ignore_install
43-
-- require('nvim-treesitter.configs').setup({
44-
-- ensure_installed = 'all',
45-
-- ignore_install = { 'org' },
46-
-- })
41+
-- Experimental LSP support
42+
vim.lsp.enable('org')
4743
end,
4844
}
4945
```

0 commit comments

Comments
 (0)