Skip to content

Commit 3669bc0

Browse files
refactor(completion)!: Extract sources to separate classes and remove nvim-compe support (nvim-orgmode#678)
1 parent 623591e commit 3669bc0

File tree

20 files changed

+633
-527
lines changed

20 files changed

+633
-527
lines changed

DOCS.md

-9
Original file line numberDiff line numberDiff line change
@@ -1248,15 +1248,6 @@ By default, `omnifunc` is provided in `org` files that autocompletes these types
12481248
* Orgfile special keywords (`#+TITLE`, `#+BEGIN_SRC`, `#+ARCHIVE`, etc.)
12491249
* Hyperlinks (`* - headlines`, `# - headlines with CUSTOM_ID property`, `headlines matching title`)
12501250

1251-
If you use [nvim-compe](https://github.com/hrsh7th/nvim-compe) add this to compe setup:
1252-
```lua
1253-
require'compe'.setup({
1254-
source = {
1255-
orgmode = true
1256-
}
1257-
})
1258-
```
1259-
12601251
For [nvim-cmp](https://github.com/hrsh7th/nvim-cmp), add `orgmode` to list of sources:
12611252
```lua
12621253
require'cmp'.setup({

README.md

-14
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,6 @@ EOF
132132
```
133133
#### Completion
134134

135-
<details>
136-
<summary><a href="https://github.com/hrsh7th/nvim-compe"><b>nvim-compe</b></a></summary>
137-
</br>
138-
139-
```lua
140-
require('compe').setup({
141-
source = {
142-
orgmode = true
143-
}
144-
})
145-
```
146-
147-
</details>
148-
149135
<details>
150136
<summary><a href="https://github.com/hrsh7th/nvim-cmp"><b>nvim-cmp</b></a></summary>
151137
</br>

ftplugin/org.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ vim.opt_local.omnifunc = 'v:lua.orgmode.omnifunc'
3131
vim.opt_local.commentstring = '# %s'
3232

3333
_G.orgmode.omnifunc = function(findstart, base)
34-
return require('orgmode.org.autocompletion.omni').omnifunc(findstart, base)
34+
return require('orgmode').completion:omnifunc(findstart, base)
3535
end
3636

3737
local abbreviations = {

lua/orgmode/init.lua

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local auto_instance_keys = {
1111
clock = true,
1212
org_mappings = true,
1313
notifications = true,
14+
completion = true,
1415
}
1516

1617
---@class Org
@@ -20,6 +21,7 @@ local auto_instance_keys = {
2021
---@field agenda OrgAgenda
2122
---@field capture OrgCapture
2223
---@field clock OrgClock
24+
---@field completion OrgCompletion
2325
---@field org_mappings OrgMappings
2426
---@field notifications OrgNotifications
2527
local Org = {}
@@ -62,7 +64,7 @@ function Org:init()
6264
self.clock = require('orgmode.clock'):new({
6365
files = self.files,
6466
})
65-
require('orgmode.org.autocompletion').register()
67+
self.completion = require('orgmode.org.autocompletion'):new({ files = self.files })
6668
self.statusline_debounced = require('orgmode.utils').debounce('statusline', function()
6769
return self.clock:get_statusline()
6870
end, 300)

lua/orgmode/objects/url.lua

+29-13
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,10 @@ local fs = require('orgmode.utils.fs')
33
---@class OrgUrl
44
---@field str string
55
local Url = {}
6-
7-
function Url:init(str)
8-
self.str = str
9-
end
6+
Url.__index = Url
107

118
function Url.new(str)
12-
local self = setmetatable({}, { __index = Url })
13-
self:init(str)
14-
return self
9+
return setmetatable({ str = str }, Url)
1510
end
1611

1712
---@return boolean
@@ -44,11 +39,6 @@ function Url:is_file_custom_id()
4439
return self:is_file() and self:get_custom_id() and true or false
4540
end
4641

47-
---@return boolean
48-
function Url:is_file_anchor()
49-
return self:get_dedicated_target() and true
50-
end
51-
5242
---@return boolean
5343
function Url:is_org_link()
5444
return (self:get_dedicated_target() or self:get_custom_id() or self:get_headline()) and true
@@ -77,7 +67,7 @@ function Url:is_internal_custom_id()
7767
end
7868

7969
function Url:is_dedicated_anchor_or_internal_title()
80-
return self:get_dedicated_target() ~= nil
70+
return self:get_dedicated_target()
8171
end
8272

8373
---@return string | false
@@ -145,6 +135,11 @@ function Url:get_linenumber()
145135
or self.str:match('^/[^:]+ %+(%d+)$')
146136
end
147137

138+
---@return string | false
139+
function Url:get_protocol()
140+
return self.str:match('^([%w]+):')
141+
end
142+
148143
---@return string | false
149144
function Url:get_filepath()
150145
return
@@ -166,6 +161,27 @@ function Url:get_filepath()
166161
or self.str:match('^(%./)$')
167162
or self.str:match('^(/)$')
168163
end
164+
165+
function Url:get_file()
166+
return
167+
-- for backwards compatibility
168+
self.str:match('^(file:[^:]+) %+%d+')
169+
or self.str:match('^(%.%./[^:]+) %+%d+')
170+
or self.str:match('^(%./[^:]+) %+%d+')
171+
or self.str:match('^(/[^:]+) %+%d+')
172+
-- official orgmode convention
173+
or self.str:match('^(file:[^:]+)::')
174+
or self.str:match('^(%.%./[^:]+)::')
175+
or self.str:match('^(%./[^:]+)::')
176+
or self.str:match('^(/[^:]+)::')
177+
or self.str:match('^(file:[^:]+)$')
178+
or self.str:match('^(%.%./[^:]+)$')
179+
or self.str:match('^(%./[^:]+)$')
180+
or self.str:match('^(/[^:]+)$')
181+
or self.str:match('^(%.%./)$')
182+
or self.str:match('^(%./)$')
183+
or self.str:match('^(/)$')
184+
end
169185
--
170186
---@return string
171187
function Url:get_headline_completion()
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---@meta
2+
3+
---@alias OrgCompletionContext { line: string, base?: string }
4+
---@alias OrgCompletionItem { word: string, menu: string }
5+
6+
---@class OrgCompletionSource
7+
---@field get_name fun(self: OrgCompletionSource): string
8+
---@field get_start fun(self: OrgCompletionSource, context: OrgCompletionContext): number | nil
9+
---@field get_results fun(self: OrgCompletionSource, context: OrgCompletionContext): string[]

lua/orgmode/org/autocompletion/cmp.lua

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ if not has_cmp then
33
return
44
end
55

6-
local Omni = require('orgmode.org.autocompletion.omni')
6+
local org = require('orgmode')
77

88
local Source = {}
99

@@ -25,9 +25,12 @@ function Source:get_trigger_characters(_)
2525
end
2626

2727
function Source:complete(params, callback)
28-
local offset = Omni.find_start() + 1
29-
local input = string.sub(params.context.cursor_before_line, offset)
30-
local results = Omni.get_completions(input)
28+
local offset = org.completion:get_start({ line = params.context.cursor_before_line }) + 1
29+
local base = string.sub(params.context.cursor_before_line, offset)
30+
local results = org.completion:complete({
31+
line = params.context.cursor_before_line,
32+
base = base,
33+
})
3134
local items = {}
3235
for _, item in ipairs(results) do
3336
table.insert(items, {

lua/orgmode/org/autocompletion/compe.lua

-42
This file was deleted.
+104-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,107 @@
1-
local function register()
2-
require('orgmode.org.autocompletion.compe')
1+
---@class OrgCompletion
2+
---@field files OrgFiles
3+
---@field private sources OrgCompletionSource[]
4+
---@field private sources_by_name table<string, OrgCompletionSource>
5+
---@field menu string
6+
local OrgCompletion = {
7+
menu = '[Org]',
8+
}
9+
OrgCompletion.__index = OrgCompletion
10+
11+
---@param opts { files: OrgFiles }
12+
function OrgCompletion:new(opts)
13+
local this = setmetatable({
14+
files = opts.files,
15+
sources = {},
16+
sources_by_name = {},
17+
}, OrgCompletion)
18+
this:setup_builtin_sources()
19+
this:register_frameworks()
20+
return this
21+
end
22+
23+
function OrgCompletion:setup_builtin_sources()
24+
self:add_source(require('orgmode.org.autocompletion.sources.todo_keywords'):new())
25+
self:add_source(require('orgmode.org.autocompletion.sources.tags'):new({ completion = self }))
26+
self:add_source(require('orgmode.org.autocompletion.sources.plan'):new({ completion = self }))
27+
self:add_source(require('orgmode.org.autocompletion.sources.directives'):new())
28+
self:add_source(require('orgmode.org.autocompletion.sources.properties'):new({ completion = self }))
29+
self:add_source(require('orgmode.org.autocompletion.sources.hyperlinks'):new({ completion = self }))
30+
end
31+
32+
---@param source OrgCompletionSource
33+
function OrgCompletion:add_source(source)
34+
if self.sources_by_name[source:get_name()] then
35+
error('Completion source ' .. source:get_name() .. ' already exists')
36+
end
37+
self.sources_by_name[source:get_name()] = source
38+
table.insert(self.sources, source)
39+
end
40+
41+
---@param context OrgCompletionContext
42+
---@return OrgCompletionItem
43+
function OrgCompletion:complete(context)
44+
local results = {}
45+
for _, source in ipairs(self.sources) do
46+
if source:get_start(context) then
47+
vim.list_extend(results, self:_get_valid_results(source:get_results(context), context))
48+
end
49+
end
50+
51+
return results
52+
end
53+
54+
function OrgCompletion:_get_valid_results(results, context)
55+
local base = context.base or ''
56+
57+
local valid_results = {}
58+
for _, item in ipairs(results) do
59+
if base == '' or item:find('^' .. vim.pesc(base)) then
60+
table.insert(valid_results, {
61+
word = item,
62+
menu = self.menu,
63+
})
64+
end
65+
end
66+
67+
return valid_results
68+
end
69+
70+
---@param context OrgCompletionContext
71+
function OrgCompletion:get_start(context)
72+
for _, source in ipairs(self.sources) do
73+
local start = source:get_start(context)
74+
if start then
75+
return start
76+
end
77+
end
78+
79+
return -1
80+
end
81+
82+
function OrgCompletion:omnifunc(findstart, base)
83+
if findstart == 1 then
84+
self._context = { line = self:get_line() }
85+
return self:get_start(self._context)
86+
end
87+
88+
self._context = self._context or { line = self:get_line() }
89+
self._context.base = base
90+
return self:complete(self._context)
91+
end
92+
93+
function OrgCompletion:get_line()
94+
local cursor = vim.api.nvim_win_get_cursor(0)
95+
return vim.api.nvim_get_current_line():sub(1, cursor[2])
96+
end
97+
98+
---@param line string
99+
function OrgCompletion:is_headline_line(line)
100+
return line:find([[^%*+%s+]]) ~= nil
101+
end
102+
103+
function OrgCompletion:register_frameworks()
3104
require('orgmode.org.autocompletion.cmp')
4105
end
5106

6-
return {
7-
register = register,
8-
}
107+
return OrgCompletion

0 commit comments

Comments
 (0)