Skip to content

Commit

Permalink
refactor(completion)!: Extract sources to separate classes and remove…
Browse files Browse the repository at this point in the history
… nvim-compe support
  • Loading branch information
kristijanhusak committed Feb 21, 2024
1 parent e042fce commit 71fad16
Show file tree
Hide file tree
Showing 20 changed files with 633 additions and 527 deletions.
9 changes: 0 additions & 9 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1248,15 +1248,6 @@ By default, `omnifunc` is provided in `org` files that autocompletes these types
* Orgfile special keywords (`#+TITLE`, `#+BEGIN_SRC`, `#+ARCHIVE`, etc.)
* Hyperlinks (`* - headlines`, `# - headlines with CUSTOM_ID property`, `headlines matching title`)

If you use [nvim-compe](https://github.com/hrsh7th/nvim-compe) add this to compe setup:
```lua
require'compe'.setup({
source = {
orgmode = true
}
})
```

For [nvim-cmp](https://github.com/hrsh7th/nvim-cmp), add `orgmode` to list of sources:
```lua
require'cmp'.setup({
Expand Down
14 changes: 0 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,6 @@ EOF
```
#### Completion

<details>
<summary><a href="https://github.com/hrsh7th/nvim-compe"><b>nvim-compe</b></a></summary>
</br>

```lua
require('compe').setup({
source = {
orgmode = true
}
})
```

</details>

<details>
<summary><a href="https://github.com/hrsh7th/nvim-cmp"><b>nvim-cmp</b></a></summary>
</br>
Expand Down
2 changes: 1 addition & 1 deletion ftplugin/org.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ vim.opt_local.omnifunc = 'v:lua.orgmode.omnifunc'
vim.opt_local.commentstring = '# %s'

_G.orgmode.omnifunc = function(findstart, base)
return require('orgmode.org.autocompletion.omni').omnifunc(findstart, base)
return require('orgmode').completion:omnifunc(findstart, base)
end

local abbreviations = {
Expand Down
4 changes: 3 additions & 1 deletion lua/orgmode/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local auto_instance_keys = {
clock = true,
org_mappings = true,
notifications = true,
completion = true
}

---@class Org
Expand All @@ -20,6 +21,7 @@ local auto_instance_keys = {
---@field agenda OrgAgenda
---@field capture OrgCapture
---@field clock OrgClock
---@field completion OrgCompletion
---@field org_mappings OrgMappings
---@field notifications OrgNotifications
local Org = {}
Expand Down Expand Up @@ -62,7 +64,7 @@ function Org:init()
self.clock = require('orgmode.clock'):new({
files = self.files,
})
require('orgmode.org.autocompletion').register()
self.completion = require('orgmode.org.autocompletion'):new({ files = self.files })
self.statusline_debounced = require('orgmode.utils').debounce('statusline', function()
return self.clock:get_statusline()
end, 300)
Expand Down
42 changes: 29 additions & 13 deletions lua/orgmode/objects/url.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ local fs = require('orgmode.utils.fs')
---@class OrgUrl
---@field str string
local Url = {}

function Url:init(str)
self.str = str
end
Url.__index = Url

function Url.new(str)
local self = setmetatable({}, { __index = Url })
self:init(str)
return self
return setmetatable({ str = str }, Url)
end

---@return boolean
Expand Down Expand Up @@ -44,11 +39,6 @@ function Url:is_file_custom_id()
return self:is_file() and self:get_custom_id() and true or false
end

---@return boolean
function Url:is_file_anchor()
return self:get_dedicated_target() and true
end

---@return boolean
function Url:is_org_link()
return (self:get_dedicated_target() or self:get_custom_id() or self:get_headline()) and true
Expand Down Expand Up @@ -77,7 +67,7 @@ function Url:is_internal_custom_id()
end

function Url:is_dedicated_anchor_or_internal_title()
return self:get_dedicated_target() ~= nil
return self:get_dedicated_target()
end

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

---@return string | false
function Url:get_protocol()
return self.str:match('^([%w]+):')
end

---@return string | false
function Url:get_filepath()
return
Expand All @@ -166,6 +161,27 @@ function Url:get_filepath()
or self.str:match('^(%./)$')
or self.str:match('^(/)$')
end

function Url:get_file()
return
-- for backwards compatibility
self.str:match('^(file:[^:]+) %+%d+')
or self.str:match('^(%.%./[^:]+) %+%d+')
or self.str:match('^(%./[^:]+) %+%d+')
or self.str:match('^(/[^:]+) %+%d+')
-- official orgmode convention
or self.str:match('^(file:[^:]+)::')
or self.str:match('^(%.%./[^:]+)::')
or self.str:match('^(%./[^:]+)::')
or self.str:match('^(/[^:]+)::')
or self.str:match('^(file:[^:]+)$')
or self.str:match('^(%.%./[^:]+)$')
or self.str:match('^(%./[^:]+)$')
or self.str:match('^(/[^:]+)$')
or self.str:match('^(%.%./)$')
or self.str:match('^(%./)$')
or self.str:match('^(/)$')
end
--
---@return string
function Url:get_headline_completion()
Expand Down
9 changes: 9 additions & 0 deletions lua/orgmode/org/autocompletion/_meta.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---@meta

---@alias OrgCompletionContext { line: string, base?: string }
---@alias OrgCompletionItem { word: string, menu: string }

---@class OrgCompletionSource
---@field get_name fun(self: OrgCompletionSource): string
---@field get_start fun(self: OrgCompletionSource, context: OrgCompletionContext): number | nil
---@field get_results fun(self: OrgCompletionSource, context: OrgCompletionContext): string[]
11 changes: 7 additions & 4 deletions lua/orgmode/org/autocompletion/cmp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ if not has_cmp then
return
end

local Omni = require('orgmode.org.autocompletion.omni')
local org = require('orgmode')

local Source = {}

Expand All @@ -25,9 +25,12 @@ function Source:get_trigger_characters(_)
end

function Source:complete(params, callback)
local offset = Omni.find_start() + 1
local input = string.sub(params.context.cursor_before_line, offset)
local results = Omni.get_completions(input)
local offset = org.completion:get_start({ line = params.context.cursor_before_line }) + 1
local base = string.sub(params.context.cursor_before_line, offset)
local results = org.completion:complete({
line = params.context.cursor_before_line,
base = base,
})
local items = {}
for _, item in ipairs(results) do
table.insert(items, {
Expand Down
42 changes: 0 additions & 42 deletions lua/orgmode/org/autocompletion/compe.lua

This file was deleted.

109 changes: 104 additions & 5 deletions lua/orgmode/org/autocompletion/init.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,107 @@
local function register()
require('orgmode.org.autocompletion.compe')
---@class OrgCompletion
---@field files OrgFiles
---@field private sources OrgCompletionSource[]
---@field private sources_by_name table<string, OrgCompletionSource>
---@field menu string
local OrgCompletion = {
menu = '[Org]',
}
OrgCompletion.__index = OrgCompletion

---@param opts { files: OrgFiles }
function OrgCompletion:new(opts)
local this = setmetatable({
files = opts.files,
sources = {},
sources_by_name = {},
}, OrgCompletion)
this:setup_builtin_sources()
this:register_frameworks()
return this
end

function OrgCompletion:setup_builtin_sources()
self:add_source(require('orgmode.org.autocompletion.sources.todo_keywords'):new())
self:add_source(require('orgmode.org.autocompletion.sources.tags'):new({ completion = self }))
self:add_source(require('orgmode.org.autocompletion.sources.plan'):new({ completion = self }))
self:add_source(require('orgmode.org.autocompletion.sources.directives'):new())
self:add_source(require('orgmode.org.autocompletion.sources.properties'):new({ completion = self }))
self:add_source(require('orgmode.org.autocompletion.sources.hyperlinks'):new({ completion = self }))
end

---@param source OrgCompletionSource
function OrgCompletion:add_source(source)
if self.sources_by_name[source:get_name()] then
error('Completion source ' .. source:get_name() .. ' already exists')
end
self.sources_by_name[source:get_name()] = source
table.insert(self.sources, source)
end

---@param context OrgCompletionContext
---@return OrgCompletionItem
function OrgCompletion:complete(context)
local results = {}
for _, source in ipairs(self.sources) do
if source:get_start(context) then
vim.list_extend(results, self:_get_valid_results(source:get_results(context), context))
end
end

return results
end

function OrgCompletion:_get_valid_results(results, context)
local base = context.base or ''

local valid_results = {}
for _, item in ipairs(results) do
if base == '' or item:find('^' .. vim.pesc(base)) then
table.insert(valid_results, {
word = item,
menu = self.menu,
})
end
end

return valid_results
end

---@param context OrgCompletionContext
function OrgCompletion:get_start(context)
for _, source in ipairs(self.sources) do
local start = source:get_start(context)
if start then
return start
end
end

return -1
end

function OrgCompletion:omnifunc(findstart, base)
if findstart == 1 then
self._context = { line = self:get_line() }
return self:get_start(self._context)
end

self._context = self._context or { line = self:get_line() }
self._context.base = base
return self:complete(self._context)
end

function OrgCompletion:get_line()
local cursor = vim.api.nvim_win_get_cursor(0)
return vim.api.nvim_get_current_line():sub(1, cursor[2])
end

---@param line string
function OrgCompletion:is_headline_line(line)
return line:find([[^%*+%s+]]) ~= nil
end

function OrgCompletion:register_frameworks()
require('orgmode.org.autocompletion.cmp')
end

return {
register = register,
}
return OrgCompletion
Loading

0 comments on commit 71fad16

Please sign in to comment.