obsidian.nvim
obsidian.nvim copied to clipboard
Support blink.nvim Autocomplete
🚀 The feature, motivation and pitch
Currently obsidian.nvim does not work with blink.nvim, only with nvim-cmp. However, as blink is gaining popularity and becoming the default for many, compatibility between blink and obsidian would be very welcome.
Alternatives
No response
Additional context
No response
https://github.com/benlubas/cmp2lsp may do the trick in the meantime? I don't know what obsidian.nvim's source name would be though, nor if it's guaranteed to be exposed
Especially, now that lazyvim has an extra for blink.nvim, I guess more and more will switch. There is also https://github.com/Saghen/blink.compat. It would be great to have an example in the docs how to configure it properly. 🤗
Edit: I managed to get the sources to blink. however, there is always an error as obsidian.nvim wants to register itself to nvim_cmp.
return {
{ "saghen/blink.compat" },
{
"saghen/blink.cmp",
dependencies = {
{ "epwalsh/obsidian.nvim" },
},
opts_extend = { "sources.completion.enabled_providers" },
---@module 'blink.cmp'
---@type blink.cmp.Config
opts = {
sources = {
completion = {
enabled_providers = {
"lsp",
"path",
"snippets",
"buffer",
"obsidian",
"obsidian_new",
"obsidian_tags",
},
},
providers = {
obsidian = {
name = "obsidian",
module = "blink.compat.source",
},
obsidian_new = {
name = "obsidian_new",
module = "blink.compat.source",
},
obsidian_tags = {
name = "obsidian_tags",
module = "blink.compat.source",
},
},
},
},
},
}
The error:
Error 08:40:08 msg_show.lua_error E5108: Error executing lua: vim/_editor.lua:0: nvim_exec2()..BufEnter Autocommands for "*.md": Vim(append):Error executing lua callback: ...ocal/share/nvim/lazy/obsidian.nvim/lua/obsidian/init.lua:151: attempt to call field 'get_config' (a nil value)
I guess https://github.com/epwalsh/obsidian.nvim/blob/main/lua/obsidian/init.lua#L143-L158 this block should be guarded.
I got autocomplete for links at least (not sure what else obsidian.nvim might provide) using the marksman language server
The permanent solution would be a LSP, not support for any given completion, cpm and blinks comes and goes. For example Neorg has its own mini LSP, you wont need to configure cmp for it
https://github.com/nvim-neorg/neorg/issues/1603#issuecomment-2480788053
LazyVim last update removed nvim-cmp in favor of blink-cmd. It would be great to see Obsidian.nvim support it !
The permanent solution would be a LSP, not support for any given completion, cpm and blinks comes and goes. For example Neorg has its own mini LSP, you wont need to configure cmp for it
Actually I take this back, I say obsidian notes are markdowns anyway, and we already have markdown LSP, so we don't need to reinvent the wheel, the mentioned LSP already supports document linking auto complete, tag auto complete, insert TOC, tree sitter highlights are also available, other functionality like toggle checkboxs etc. actually I disabled the obsidian plugin entirely and I could do almost my daily workflow on my vaults.
In my humble opinion, the easiest, still most maintainable and extendable breakthrough, is to keep obsidian plugin, only related to obsidian specific functionalities like managing the vaults, referencing the tags/files (BY USING THE MD LSP, again not reinventing the wheel), front matter, opening the MD in obsidian etc.
Managing the highlights, auto complete anything, toggle the checkbox etc are done more maturely in markdown lsp
LazyVim last update removed nvim-cmp in favor of blink-cmd. It would be great to see Obsidian.nvim support it !
Yep, would be awesome! My workaround is to enable nvim-cmp again in the extras.
return {
{
"epwalsh/obsidian.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
},
opts = {
completion = {
nvim_cmp = false, -- disable!
},
},
config = function(_, opts)
require("obsidian").setup(opts)
-- HACK: fix error, disable completion.nvim_cmp option, manually register sources
local cmp = require("cmp")
cmp.register_source("obsidian", require("cmp_obsidian").new())
cmp.register_source("obsidian_new", require("cmp_obsidian_new").new())
cmp.register_source("obsidian_tags", require("cmp_obsidian_tags").new())
end,
},
{
"saghen/blink.cmp",
dependencies = { "saghen/blink.compat" },
opts = {
sources = {
default = { "obsidian", "obsidian_new", "obsidian_tags" },
providers = {
obsidian = {
name = "obsidian",
module = "blink.compat.source",
},
obsidian_new = {
name = "obsidian_new",
module = "blink.compat.source",
},
obsidian_tags = {
name = "obsidian_tags",
module = "blink.compat.source",
},
},
},
},
},
}
@yuchenfei doesn't this still require nvim cmp to be installed?
@yuchenfei doesn't this still require nvim cmp to be installed?
It does. You're registering obsidian sources with cmp and then using them in blink. It's a workaround not a replacement right now.
@yuchenfei doesn't this still require nvim cmp to be installed?
Yes, it still requires nvim-cmp, but it only loads when completing in Obsidian notes. This is a workaround configuration to make it work for now.
Oh, thank you. I initially did that without registering the source. I'll do this.
@yuchenfei @sebszyller @Muizzyranking author of blink.compat here. FYI, when using blink.compat, nvim-cmp should not be installed. blink.compat mirrors the cmp api, including the cmp.register_source function you are using. I'll take a look at adding the cmp.get_config function as well so that this works out of the box.
I have been using the same above change mentioned by @yuchenfei and I am not sure if I am doing something wrong. I keep getting this error: failed to get completions with error: ...share/nvim/lazy/blink.compat/lua/blink/compat/source.lua:87: attempt to index local 'item' (a boolean value)
Here's my obsidian lua configuration:
return {
{
"epwalsh/obsidian.nvim",
version = "*",
lazy = false,
ft = "markdown",
dependencies = {
"nvim-lua/plenary.nvim",
},
opts = {
workspaces = {
{
name = "wiki",
path = "/Users/shivayanbora/PKM/My-Wiki-Vault",
},
},
new_notes_location = "notes_subdir",
notes_subdir = "0_inbox",
note_frontmatter_func = function(note)
-- Add the title of the note as an alias.
if note.title then
note:add_alias(note.title)
end
local out = {
id = note.id,
aliases = note.aliases,
tags = note.tags,
}
-- `note.metadata` contains any manually added fields in the frontmatter.
-- So here we just make sure those fields are kept in the frontmatter.
if note.metadata ~= nil and not vim.tbl_isempty(note.metadata) then
for k, v in pairs(note.metadata) do
out[k] = v
end
end
return out
end,
-- Optional, customize how note IDs are generated given an optional title.
---@param title string|?
---@return string
note_id_func = function(title)
-- Create note IDs in a Zettelkasten format with a timestamp and a suffix.
-- In this case a note with the title 'My new note' will be given an ID that looks
-- like '1657296016-my-new-note', and therefore the file name '1657296016-my-new-note.md'
local suffix = ""
if title ~= nil then
-- If title is given, transform it into valid file name.
suffix = title:gsub(" ", "-"):gsub("[^A-Za-z0-9-]", ""):lower()
else
-- If title is nil, just add 4 random uppercase letters to the suffix.
for _ = 1, 4 do
suffix = suffix .. string.char(math.random(65, 90))
end
end
return tostring(os.time()) .. "-" .. suffix
end,
-- Optional, customize how note file names are generated given the ID, target directory, and title.
---@param spec { id: string, dir: obsidian.Path, title: string|? }
---@return string|obsidian.Path The full path to the new note.
note_path_func = function(spec)
-- This is equivalent to the default behavior.
local path = spec.dir / tostring(spec.id)
return path:with_suffix(".md")
end,
templates = {
folder = "templates",
date_format = "%Y-%m-%d",
time_format = "%H:%M:%S",
},
completion = {
nvim_cmp = false,
min_chars = 2,
},
ui = {
enable = false,
},
},
config = function(_, opts)
require("obsidian").setup(opts)
local cmp = require("cmp")
cmp.register_source("obsidian", require("cmp_obsidian").new())
cmp.register_source("obsidian_new", require("cmp_obsidian_new").new())
cmp.register_source("obsidian_tags", require("cmp_obsidian_tags").new())
end,
},
{
"saghen/blink.cmp",
dependencies = { "saghen/blink.compat" },
opts = {
sources = {
default = { "obsidian", "obsidian_new", "obsidian_tags" },
providers = {
obsidian = {
name = "obsidian",
module = "blink.compat.source",
},
obsidian_new = {
name = "obsidian_new",
module = "blink.compat.source",
},
obsidian_tags = {
name = "obsidian_tags",
module = "blink.compat.source",
},
},
},
},
},
}
@stefanboca could you post a config here to make it work with obsidian or maybe mention it in the blink readme? 😬
I have been using the same above change mentioned by @yuchenfei and I am not sure if I am doing something wrong. I keep getting this error:
failed to get completions with error: ...share/nvim/lazy/blink.compat/lua/blink/compat/source.lua:87: attempt to index local 'item' (a boolean value)
Just switch the blink.compat to main branch
@CaeChao Am I doing this correctly? Sorry I am quite new to Neovim.
return {
{
"epwalsh/obsidian.nvim",
version = "*",
lazy = false,
ft = "markdown",
dependencies = {
"nvim-lua/plenary.nvim",
},
opts = {
workspaces = {
{
name = "wiki",
path = "/Users/shivayanbora/PKM/My-Wiki-Vault",
},
},
new_notes_location = "notes_subdir",
notes_subdir = "0_inbox",
note_frontmatter_func = function(note)
-- Add the title of the note as an alias.
if note.title then
note:add_alias(note.title)
end
local out = {
id = note.id,
aliases = note.aliases,
tags = note.tags,
}
-- `note.metadata` contains any manually added fields in the frontmatter.
-- So here we just make sure those fields are kept in the frontmatter.
if note.metadata ~= nil and not vim.tbl_isempty(note.metadata) then
for k, v in pairs(note.metadata) do
out[k] = v
end
end
return out
end,
-- Optional, customize how note IDs are generated given an optional title.
---@param title string|?
---@return string
note_id_func = function(title)
-- Create note IDs in a Zettelkasten format with a timestamp and a suffix.
-- In this case a note with the title 'My new note' will be given an ID that looks
-- like '1657296016-my-new-note', and therefore the file name '1657296016-my-new-note.md'
local suffix = ""
if title ~= nil then
-- If title is given, transform it into valid file name.
suffix = title:gsub(" ", "-"):gsub("[^A-Za-z0-9-]", ""):lower()
else
-- If title is nil, just add 4 random uppercase letters to the suffix.
for _ = 1, 4 do
suffix = suffix .. string.char(math.random(65, 90))
end
end
return tostring(os.time()) .. "-" .. suffix
end,
-- Optional, customize how note file names are generated given the ID, target directory, and title.
---@param spec { id: string, dir: obsidian.Path, title: string|? }
---@return string|obsidian.Path The full path to the new note.
note_path_func = function(spec)
-- This is equivalent to the default behavior.
local path = spec.dir / tostring(spec.id)
return path:with_suffix(".md")
end,
templates = {
folder = "templates",
date_format = "%Y-%m-%d",
time_format = "%H:%M:%S",
},
completion = {
nvim_cmp = false,
min_chars = 2,
},
ui = {
enable = false,
},
},
config = function(_, opts)
require("obsidian").setup(opts)
local cmp = require("cmp")
cmp.register_source("obsidian", require("cmp_obsidian").new())
cmp.register_source("obsidian_new", require("cmp_obsidian_new").new())
cmp.register_source("obsidian_tags", require("cmp_obsidian_tags").new())
end,
},
{
"saghen/blink.cmp",
dependencies = {
{ "saghen/blink.compat", branch = "main" },
},
opts = {
sources = {
default = { "obsidian", "obsidian_new", "obsidian_tags" },
providers = {
obsidian = {
name = "obsidian",
module = "blink.compat.source",
},
obsidian_new = {
name = "obsidian_new",
module = "blink.compat.source",
},
obsidian_tags = {
name = "obsidian_tags",
module = "blink.compat.source",
},
},
},
},
},
}
If yes, I am still getting the error: failed to get completions with error: ...share/nvim/lazy/blink.compat/lua/blink/compat/source.lua:87: attempt to index local 'item' (a boolean value)
Just for context:
UPDATE:
I deleted ~/.local/share/nvim and ~/.local/state/nvim and reinstalled everything. Still the same issue.
@shivayan-bora remove the part where you registered the source with CMP, blink compat's author said it wasn't necessary.
@shivayan-bora I believe you also need version = "*" for the saghen/blink.compat plugin until https://github.com/epwalsh/obsidian.nvim/issues/770#issuecomment-2558570918 is released.
@shivayan-bora my guess is that you are using LazyVim, so you need to put version = false inside { "saghen/blink.compat", lazy = true, version = false } to override the default setting from LazyVIm
or set vim.g.lazyvim_blink_main = true in your options.lua file
or you can just wait for the next release....
@Muizzyranking I think you still need the registered part above to make it work, blink.compat just mirror the CMP module, obsidian need to call the api in order to register the sources
It's working perfectly for me with this configuration:
https://github.com/Gentleman-Programming/Gentleman.Dots/blob/main/GentlemanNvim/nvim/lua/plugins/obsidian.lua
@CaeChao blink.compat author said it wasn't neccessary.
@Alan-TheGentleman this is very similar to what I have too.
Well, I've tried to follow all pieces of advice, but it doesn't work on my side… No more completion with my LazyVim config. I had to set nvim-cpm to false :(
I guess I'll wait for the next obsidian.nvim version and I hope it will be able to auto-detect the config (for newbies like me !) when nvim-cmp is set to true.
@celfred can you share a snippet of what you did? Because for LazyVim, there is a custom spec to pass in custom sources as a list so you won't have to add the module, look at this extra for example. I am not with my pc at the moment but if I see your config, I could help you write LazyVim compatible config.
Thanks @Muizzyranking for this quick reply. I'm not sure how your link can help me… sorry…
What I've done so far :
-
I added this at the end of my 'opts= {} ' in my obsidian.nvim file (in my plugins directory) :
` config = function(_, opts) require("obsidian").setup(opts)-- HACK: fix error, disable completion.nvim_cmp option, manually register sources local cmp = require("cmp") cmp.register_source("obsidian", require("cmp_obsidian").new()) cmp.register_source("obsidian_new", require("cmp_obsidian_new").new()) cmp.register_source("obsidian_tags", require("cmp_obsidian_tags").new()) end, `
-
I added this right after my 'opts={}' block :
{ "saghen/blink.cmp", dependencies = { "saghen/blink.compat" }, opts = { sources = { default = { "obsidian", "obsidian_new", "obsidian_tags" }, providers = { obsidian = { name = "obsidian", module = "blink.compat.source", }, obsidian_new = { name = "obsidian_new", module = "blink.compat.source", }, obsidian_tags = { name = "obsidian_tags", module = "blink.compat.source", }, }, }, }, }, -
I added this line in my 'config > options.lua' file :
vim.g.lazyvim_blink_main = true
Don't know if that explains anything… But thanks for your time !
@celfred As a workaround I suggest you use marskman LSP.
@celfred As a workaround I suggest you use
marskmanLSP.
Well, I've read that suggestion too earlier, but I had no idea how to set up marksman LSP instead of what I'm using right now…
@celfred I just got hold of my PC, first of all remove the hack to register source in obsidian with cmp, blink compat has it covered
for blink you can do this
{
"saghen/blink.cmp",
dependencies = {
{ "epwalsh/obsidian.nvim", "saghen/blink.compat" },
},
opts = {
sources = {
-- LazyVim as custom option copmpat to pass in external sources with blink.compat
compat = { "obsidian", "obsidian_new", "obsidian_tags" },
-- Optional to set kind name., not really neccesary.
-- providers = {
-- obsidian = {
-- kind = "Obsidian",
-- async = true,
-- },
-- obsidian_new = {
-- kind = "Obsidian",
-- async = true,
-- },
-- obsidian_tags = {
-- kind = "Obsidian",
-- async = true,
-- },
-- },
},
},
}
To setup marksman lsp in lazyvim, go to your lazy.lua file and add this to the spec table.
{ import = "lazyvim.plugins.extras.lang.markdown" },
I will suggest you read LazyVim docs on how to extend/override plugins opts and importing extras. You might also need to peek the source code to get a better understanding.
@Muizzyranking Your solution is basically ignoring the Obsidian source and replace it with Makrsman lsp as source. The author of blink.compat said you should not install nvim-cmp instead of ignoring the register part.
The main branch of blink.compat has already implemented a workaround for obsidian Just switch the blink.compat version to main like this
{
"saghen/blink.cmp",
dependencies = {
{ "saghen/blink.compat", lazy = true, version = false }, },
},
...
}
and put the nvim_cmp back to true and it will work fine now
@CaeChao putting nvim_cmp to true would cause some errors, set it to false and blink.compat would deal with registering the sources.