[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-70613":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":31,"readmeContent":32,"aiSummary":33,"trendingCount":16,"starSnapshotCount":16,"syncStatus":34,"lastSyncTime":35,"discoverSource":36},70613,"obsidian.nvim","epwalsh\u002Fobsidian.nvim","epwalsh","Obsidian 🤝 Neovim","",null,"Lua",6103,251,19,162,0,4,44,12,38.2,"Apache License 2.0",false,"main",true,[26,27,28,29,30],"neovim","neovim-lua","neovim-plugin","nvim","nvim-cmp","2026-06-12 02:02:35","\u003Ch1 align=\"center\">obsidian.nvim\u003C\u002Fh1>\n\u003Cdiv>\u003Ch4 align=\"center\">\u003Ca href=\"#setup\">Setup\u003C\u002Fa> · \u003Ca href=\"#configuration-options\">Configure\u003C\u002Fa> · \u003Ca href=\"#contributing\">Contribute\u003C\u002Fa> · \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fdiscussions\">Discuss\u003C\u002Fa>\u003C\u002Fh4>\u003C\u002Fdiv>\n\u003Cdiv align=\"center\">\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Freleases\u002Flatest\">\u003Cimg alt=\"Latest release\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Fepwalsh\u002Fobsidian.nvim?style=for-the-badge&logo=starship&logoColor=D9E0EE&labelColor=302D41&&color=d9b3ff&include_prerelease&sort=semver\" \u002F>\u003C\u002Fa> \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fpulse\">\u003Cimg alt=\"Last commit\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flast-commit\u002Fepwalsh\u002Fobsidian.nvim?style=for-the-badge&logo=github&logoColor=D9E0EE&labelColor=302D41&color=9fdf9f\"\u002F>\u003C\u002Fa> \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fneovim\u002Fneovim\u002Freleases\u002Flatest\">\u003Cimg alt=\"Latest Neovim\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Fneovim\u002Fneovim?style=for-the-badge&logo=neovim&logoColor=D9E0EE&label=Neovim&labelColor=302D41&color=99d6ff&sort=semver\" \u002F>\u003C\u002Fa> \u003Ca href=\"http:\u002F\u002Fwww.lua.org\u002F\">\u003Cimg alt=\"Made with Lua\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FBuilt%20with%20Lua-grey?style=for-the-badge&logo=lua&logoColor=D9E0EE&label=Lua&labelColor=302D41&color=b3b3ff\">\u003C\u002Fa> \u003Ca href=\"https:\u002F\u002Fwww.buymeacoffee.com\u002Fepwalsh\">\u003Cimg alt=\"Buy me a coffee\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FBuy%20me%20a%20coffee-grey?style=for-the-badge&logo=buymeacoffee&logoColor=D9E0EE&label=Sponsor&labelColor=302D41&color=ffff99\" \u002F>\u003C\u002Fa>\u003C\u002Fdiv>\n\u003Chr>\n\nA Neovim plugin for writing and navigating [Obsidian](https:\u002F\u002Fobsidian.md) vaults, written in Lua.\n\nBuilt for people who love the concept of Obsidian -- a simple, markdown-based notes app -- but love Neovim too much to stand typing characters into anything else.\n\nIf you're new to Obsidian I highly recommend watching [this excellent YouTube video](https:\u002F\u002Fyoutu.be\u002F5ht8NYkU9wQ?si=8nbnNsRVnw0xfX2S) for a great overview.\n\n_Keep in mind this plugin is not meant to replace Obsidian, but to complement it._ The Obsidian app is very powerful in its own way; it comes with a mobile app and has a lot of functionality that's not feasible to implement in Neovim, such as the graph explorer view. That said, this plugin stands on its own as well. You don't necessarily need to use it alongside the Obsidian app.\n\n## Table of contents\n\n- 👉 [Features](#features)\n  - [Commands](#commands)\n  - [Demo](#demo)\n- ⚙️ [Setup](#setup)\n  - [System requirements](#system-requirements)\n  - [Install and configure](#install-and-configure)\n  - [Plugin dependencies](#plugin-dependencies)\n  - [Configuration options](#configuration-options)\n  - [Notes on configuration](#notes-on-configuration)\n  - [Using templates](#using-templates)\n  - [Usage outside of a workspace or vault](#usage-outside-of-a-workspace-or-vault)\n- ➕ [Contributing](#contributing)\n\n## Features\n\n▶️ **Completion:** Ultra-fast, asynchronous autocompletion for note references and tags via [nvim-cmp](https:\u002F\u002Fgithub.com\u002Fhrsh7th\u002Fnvim-cmp) (triggered by typing `[[` for wiki links, `[` for markdown links, or `#` for tags), powered by [`ripgrep`](https:\u002F\u002Fgithub.com\u002FBurntSushi\u002Fripgrep).\n\n[![See this screenshot](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002F90d5f218-06cd-4ebb-b00b-b59c2f5c3cc1)](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002F90d5f218-06cd-4ebb-b00b-b59c2f5c3cc1)\n\n🏃 **Navigation:** Navigate throughout your vault by typing `gf` on any link to another note.\n\n📷 **Images:** Paste images into notes.\n\n💅 **Syntax:** Additional markdown syntax highlighting, concealing, and extmarks for references, tags, and check-boxes.\n\n[![See this screenshot](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002Fe74f5267-21b5-49bc-a3bb-3b9db5fa6687)](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002Fe74f5267-21b5-49bc-a3bb-3b9db5fa6687)\n\n### Commands\n\n- `:ObsidianOpen [QUERY]` to open a note in the Obsidian app.\n  This command has one optional argument: a query used to resolve the note to open by ID, path, or alias. If not given, the note corresponding to the current buffer is opened.\n\n- `:ObsidianNew [TITLE]` to create a new note.\n  This command has one optional argument: the title of the new note.\n\n- `:ObsidianQuickSwitch` to quickly switch to (or open) another note in your vault, searching by its name using [ripgrep](https:\u002F\u002Fgithub.com\u002FBurntSushi\u002Fripgrep) with your preferred picker (see [plugin dependencies](#plugin-dependencies) below).\n\n- `:ObsidianFollowLink [vsplit|hsplit]` to follow a note reference under the cursor, optionally opening it in a vertical or horizontal split.\n\n- `:ObsidianBacklinks` for getting a picker list of references to the current buffer.\n\n- `:ObsidianTags [TAG ...]` for getting a picker list of all occurrences of the given tags.\n\n- `:ObsidianToday [OFFSET]` to open\u002Fcreate a new daily note. This command also takes an optional offset in days, e.g. use `:ObsidianToday -1` to go to yesterday's note. Unlike `:ObsidianYesterday` and `:ObsidianTomorrow` this command does not differentiate between weekdays and weekends.\n\n- `:ObsidianYesterday` to open\u002Fcreate the daily note for the previous working day.\n\n- `:ObsidianTomorrow` to open\u002Fcreate the daily note for the next working day.\n\n- `:ObsidianDailies [OFFSET ...]` to open a picker list of daily notes. For example, `:ObsidianDailies -2 1` to list daily notes from 2 days ago until tomorrow.\n\n- `:ObsidianTemplate [NAME]` to insert a template from the templates folder, selecting from a list using your preferred picker. See [\"using templates\"](#using-templates) for more information.\n\n- `:ObsidianSearch [QUERY]` to search for (or create) notes in your vault using `ripgrep` with your preferred picker.\n\n- `:ObsidianLink [QUERY]` to link an inline visual selection of text to a note.\n  This command has one optional argument: a query that will be used to resolve the note by ID, path, or alias. If not given, the selected text will be used as the query.\n\n- `:ObsidianLinkNew [TITLE]` to create a new note and link it to an inline visual selection of text.\n  This command has one optional argument: the title of the new note. If not given, the selected text will be used as the title.\n\n- `:ObsidianLinks` to collect all links within the current buffer into a picker window.\n\n- `:ObsidianExtractNote [TITLE]` to extract the visually selected text into a new note and link to it.\n\n- `:ObsidianWorkspace [NAME]` to switch to another workspace.\n\n- `:ObsidianPasteImg [IMGNAME]` to paste an image from the clipboard into the note at the cursor position by saving it to the vault and adding a markdown image link. You can configure the default folder to save images to with the `attachments.img_folder` option.\n\n- `:ObsidianRename [NEWNAME] [--dry-run]` to rename the note of the current buffer or reference under the cursor, updating all backlinks across the vault. Since this command is still relatively new and could potentially write a lot of changes to your vault, I highly recommend committing the current state of your vault (if you're using version control) before running it, or doing a dry-run first by appending \"--dry-run\" to the command, e.g. `:ObsidianRename new-id --dry-run`.\n\n- `:ObsidianToggleCheckbox` to cycle through checkbox options.\n\n- `:ObsidianNewFromTemplate [TITLE]` to create a new note from a template in the templates folder. Selecting from a list using your preferred picker.\n  This command has one optional argument: the title of the new note.\n\n- `:ObsidianTOC` to load the table of contents of the current note into a picker list.\n\n### Demo\n\n[![2024-01-31 14 22 52](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002F2986e1d2-13e8-40e2-9c9e-75691a3b662e)](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fassets\u002F8812459\u002F2986e1d2-13e8-40e2-9c9e-75691a3b662e)\n\n## Setup\n\n### System requirements\n\n- NeoVim >= 0.8.0 (this plugin uses `vim.fs` which was only added in 0.8).\n- If you want completion and search features (recommended) you'll need [ripgrep](https:\u002F\u002Fgithub.com\u002FBurntSushi\u002Fripgrep) to be installed and on your `$PATH`.\n  See [ripgrep#installation](https:\u002F\u002Fgithub.com\u002FBurntSushi\u002Fripgrep) for install options.\n\nSpecific operating systems also require additional dependencies in order to use all of obsidian.nvim's functionality:\n\n- **Windows WSL** users need [`wsl-open`](https:\u002F\u002Fgitlab.com\u002F4U6U57\u002Fwsl-open) for the `:ObsidianOpen` command.\n- **MacOS** users need [`pngpaste`](https:\u002F\u002Fgithub.com\u002Fjcsalterego\u002Fpngpaste) (`brew install pngpaste`) for the `:ObsidianPasteImg` command.\n- **Linux** users need xclip (X11) or wl-clipboard (Wayland) for the `:ObsidianPasteImg` command.\n\nSearch functionality (e.g. via the `:ObsidianSearch` and `:ObsidianQuickSwitch` commands) also requires a picker such [telescope.nvim](https:\u002F\u002Fgithub.com\u002Fnvim-telescope\u002Ftelescope.nvim) (see [plugin dependencies](#plugin-dependencies) below).\n\n### Install and configure\n\nTo configure obsidian.nvim you just need to call `require(\"obsidian\").setup({ ... })` with the desired options.\nHere are some examples using different plugin managers. The full set of [plugin dependencies](#plugin-dependencies) and [configuration options](#configuration-options) are listed below.\n\n> ⚠️ WARNING: if you install from the latest release (recommended for stability) instead of `main`, be aware that the README on `main` may reference features that haven't been released yet. For that reason I recommend viewing the README on the tag for the [latest release](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Freleases) instead of `main`.\n\n#### Using [`lazy.nvim`](https:\u002F\u002Fgithub.com\u002Ffolke\u002Flazy.nvim)\n\n```lua\nreturn {\n  \"epwalsh\u002Fobsidian.nvim\",\n  version = \"*\",  -- recommended, use latest release instead of latest commit\n  lazy = true,\n  ft = \"markdown\",\n  -- Replace the above line with this if you only want to load obsidian.nvim for markdown files in your vault:\n  -- event = {\n  --   -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'.\n  --   -- E.g. \"BufReadPre \" .. vim.fn.expand \"~\" .. \"\u002Fmy-vault\u002F*.md\"\n  --   -- refer to `:h file-pattern` for more examples\n  --   \"BufReadPre path\u002Fto\u002Fmy-vault\u002F*.md\",\n  --   \"BufNewFile path\u002Fto\u002Fmy-vault\u002F*.md\",\n  -- },\n  dependencies = {\n    -- Required.\n    \"nvim-lua\u002Fplenary.nvim\",\n\n    -- see below for full list of optional dependencies 👇\n  },\n  opts = {\n    workspaces = {\n      {\n        name = \"personal\",\n        path = \"~\u002Fvaults\u002Fpersonal\",\n      },\n      {\n        name = \"work\",\n        path = \"~\u002Fvaults\u002Fwork\",\n      },\n    },\n\n    -- see below for full list of options 👇\n  },\n}\n```\n\n#### Using [`packer.nvim`](https:\u002F\u002Fgithub.com\u002Fwbthomason\u002Fpacker.nvim)\n\n```lua\nuse({\n  \"epwalsh\u002Fobsidian.nvim\",\n  tag = \"*\",  -- recommended, use latest release instead of latest commit\n  requires = {\n    -- Required.\n    \"nvim-lua\u002Fplenary.nvim\",\n\n    -- see below for full list of optional dependencies 👇\n  },\n  config = function()\n    require(\"obsidian\").setup({\n      workspaces = {\n        {\n          name = \"personal\",\n          path = \"~\u002Fvaults\u002Fpersonal\",\n        },\n        {\n          name = \"work\",\n          path = \"~\u002Fvaults\u002Fwork\",\n        },\n      },\n\n      -- see below for full list of options 👇\n    })\n  end,\n})\n```\n\n### Plugin dependencies\n\nThe only **required** plugin dependency is [plenary.nvim](https:\u002F\u002Fgithub.com\u002Fnvim-lua\u002Fplenary.nvim), but there are a number of optional dependencies that enhance the obsidian.nvim experience.\n\n**Completion:**\n\n- **[recommended]** [hrsh7th\u002Fnvim-cmp](https:\u002F\u002Fgithub.com\u002Fhrsh7th\u002Fnvim-cmp): for completion of note references.\n\n**Pickers:**\n\n- **[recommended]** [nvim-telescope\u002Ftelescope.nvim](https:\u002F\u002Fgithub.com\u002Fnvim-telescope\u002Ftelescope.nvim): for search and quick-switch functionality.\n- [Mini.Pick](https:\u002F\u002Fgithub.com\u002Fechasnovski\u002Fmini.pick) from the mini.nvim library: an alternative to telescope for search and quick-switch functionality.\n- [ibhagwan\u002Ffzf-lua](https:\u002F\u002Fgithub.com\u002Fibhagwan\u002Ffzf-lua): another alternative to telescope for search and quick-switch functionality.\n\n**Syntax highlighting:**\n\n- **[recommended]** [nvim-treesitter](https:\u002F\u002Fgithub.com\u002Fnvim-treesitter\u002Fnvim-treesitter): for base markdown syntax highlighting. See [syntax highlighting](#syntax-highlighting) for more details.\n- [preservim\u002Fvim-markdown](https:\u002F\u002Fgithub.com\u002Fpreservim\u002Fvim-markdown): an alternative to nvim-treesitter for syntax highlighting (see [syntax highlighting](#syntax-highlighting) for more details), plus other cool features.\n\n**Miscellaneous:**\n\n- 🆕 [pomo.nvim](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fpomo.nvim): for running lightweight [pomodoro](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPomodoro_Technique) timers.\n\nIf you choose to use any of these you should include them in the \"dependencies\" or \"requires\" field of the obsidian.nvim plugin spec for your package manager.\n\n### Configuration options\n\nThis is a complete list of all of the options that can be passed to `require(\"obsidian\").setup()`. The settings below are *not necessarily the defaults, but represent reasonable default settings*. Please read each option carefully and customize it to your needs:\n\n```lua\n{\n  -- A list of workspace names, paths, and configuration overrides.\n  -- If you use the Obsidian app, the 'path' of a workspace should generally be\n  -- your vault root (where the `.obsidian` folder is located).\n  -- When obsidian.nvim is loaded by your plugin manager, it will automatically set\n  -- the workspace to the first workspace in the list whose `path` is a parent of the\n  -- current markdown file being edited.\n  workspaces = {\n    {\n      name = \"personal\",\n      path = \"~\u002Fvaults\u002Fpersonal\",\n    },\n    {\n      name = \"work\",\n      path = \"~\u002Fvaults\u002Fwork\",\n      -- Optional, override certain settings.\n      overrides = {\n        notes_subdir = \"notes\",\n      },\n    },\n  },\n\n  -- Alternatively - and for backwards compatibility - you can set 'dir' to a single path instead of\n  -- 'workspaces'. For example:\n  -- dir = \"~\u002Fvaults\u002Fwork\",\n\n  -- Optional, if you keep notes in a specific subdirectory of your vault.\n  notes_subdir = \"notes\",\n\n  -- Optional, set the log level for obsidian.nvim. This is an integer corresponding to one of the log\n  -- levels defined by \"vim.log.levels.*\".\n  log_level = vim.log.levels.INFO,\n\n  daily_notes = {\n    -- Optional, if you keep daily notes in a separate directory.\n    folder = \"notes\u002Fdailies\",\n    -- Optional, if you want to change the date format for the ID of daily notes.\n    date_format = \"%Y-%m-%d\",\n    -- Optional, if you want to change the date format of the default alias of daily notes.\n    alias_format = \"%B %-d, %Y\",\n    -- Optional, default tags to add to each new daily note created.\n    default_tags = { \"daily-notes\" },\n    -- Optional, if you want to automatically insert a template from your template directory like 'daily.md'\n    template = nil\n  },\n\n  -- Optional, completion of wiki links, local markdown links, and tags using nvim-cmp.\n  completion = {\n    -- Set to false to disable completion.\n    nvim_cmp = true,\n    -- Trigger completion at 2 chars.\n    min_chars = 2,\n  },\n\n  -- Optional, configure key mappings. These are the defaults. If you don't want to set any keymappings this\n  -- way then set 'mappings = {}'.\n  mappings = {\n    -- Overrides the 'gf' mapping to work on markdown\u002Fwiki links within your vault.\n    [\"gf\"] = {\n      action = function()\n        return require(\"obsidian\").util.gf_passthrough()\n      end,\n      opts = { noremap = false, expr = true, buffer = true },\n    },\n    -- Toggle check-boxes.\n    [\"\u003Cleader>ch\"] = {\n      action = function()\n        return require(\"obsidian\").util.toggle_checkbox()\n      end,\n      opts = { buffer = true },\n    },\n    -- Smart action depending on context, either follow link or toggle checkbox.\n    [\"\u003Ccr>\"] = {\n      action = function()\n        return require(\"obsidian\").util.smart_action()\n      end,\n      opts = { buffer = true, expr = true },\n    }\n  },\n\n  -- Where to put new notes. Valid options are\n  --  * \"current_dir\" - put new notes in same directory as the current buffer.\n  --  * \"notes_subdir\" - put new notes in the default notes subdirectory.\n  new_notes_location = \"notes_subdir\",\n\n  -- Optional, customize how note IDs are generated given an optional title.\n  ---@param title string|?\n  ---@return string\n  note_id_func = function(title)\n    -- Create note IDs in a Zettelkasten format with a timestamp and a suffix.\n    -- In this case a note with the title 'My new note' will be given an ID that looks\n    -- like '1657296016-my-new-note', and therefore the file name '1657296016-my-new-note.md'\n    local suffix = \"\"\n    if title ~= nil then\n      -- If title is given, transform it into valid file name.\n      suffix = title:gsub(\" \", \"-\"):gsub(\"[^A-Za-z0-9-]\", \"\"):lower()\n    else\n      -- If title is nil, just add 4 random uppercase letters to the suffix.\n      for _ = 1, 4 do\n        suffix = suffix .. string.char(math.random(65, 90))\n      end\n    end\n    return tostring(os.time()) .. \"-\" .. suffix\n  end,\n\n  -- Optional, customize how note file names are generated given the ID, target directory, and title.\n  ---@param spec { id: string, dir: obsidian.Path, title: string|? }\n  ---@return string|obsidian.Path The full path to the new note.\n  note_path_func = function(spec)\n    -- This is equivalent to the default behavior.\n    local path = spec.dir \u002F tostring(spec.id)\n    return path:with_suffix(\".md\")\n  end,\n\n  -- Optional, customize how wiki links are formatted. You can set this to one of:\n  --  * \"use_alias_only\", e.g. '[[Foo Bar]]'\n  --  * \"prepend_note_id\", e.g. '[[foo-bar|Foo Bar]]'\n  --  * \"prepend_note_path\", e.g. '[[foo-bar.md|Foo Bar]]'\n  --  * \"use_path_only\", e.g. '[[foo-bar.md]]'\n  -- Or you can set it to a function that takes a table of options and returns a string, like this:\n  wiki_link_func = function(opts)\n    return require(\"obsidian.util\").wiki_link_id_prefix(opts)\n  end,\n\n  -- Optional, customize how markdown links are formatted.\n  markdown_link_func = function(opts)\n    return require(\"obsidian.util\").markdown_link(opts)\n  end,\n\n  -- Either 'wiki' or 'markdown'.\n  preferred_link_style = \"wiki\",\n\n  -- Optional, boolean or a function that takes a filename and returns a boolean.\n  -- `true` indicates that you don't want obsidian.nvim to manage frontmatter.\n  disable_frontmatter = false,\n\n  -- Optional, alternatively you can customize the frontmatter data.\n  ---@return table\n  note_frontmatter_func = function(note)\n    -- Add the title of the note as an alias.\n    if note.title then\n      note:add_alias(note.title)\n    end\n\n    local out = { id = note.id, aliases = note.aliases, tags = note.tags }\n\n    -- `note.metadata` contains any manually added fields in the frontmatter.\n    -- So here we just make sure those fields are kept in the frontmatter.\n    if note.metadata ~= nil and not vim.tbl_isempty(note.metadata) then\n      for k, v in pairs(note.metadata) do\n        out[k] = v\n      end\n    end\n\n    return out\n  end,\n\n  -- Optional, for templates (see below).\n  templates = {\n    folder = \"templates\",\n    date_format = \"%Y-%m-%d\",\n    time_format = \"%H:%M\",\n    -- A map for custom variables, the key should be the variable and the value a function\n    substitutions = {},\n  },\n\n  -- Optional, by default when you use `:ObsidianFollowLink` on a link to an external\n  -- URL it will be ignored but you can customize this behavior here.\n  ---@param url string\n  follow_url_func = function(url)\n    -- Open the URL in the default web browser.\n    vim.fn.jobstart({\"open\", url})  -- Mac OS\n    -- vim.fn.jobstart({\"xdg-open\", url})  -- linux\n    -- vim.cmd(':silent exec \"!start ' .. url .. '\"') -- Windows\n    -- vim.ui.open(url) -- need Neovim 0.10.0+\n  end,\n\n  -- Optional, by default when you use `:ObsidianFollowLink` on a link to an image\n  -- file it will be ignored but you can customize this behavior here.\n  ---@param img string\n  follow_img_func = function(img)\n    vim.fn.jobstart { \"qlmanage\", \"-p\", img }  -- Mac OS quick look preview\n    -- vim.fn.jobstart({\"xdg-open\", url})  -- linux\n    -- vim.cmd(':silent exec \"!start ' .. url .. '\"') -- Windows\n  end,\n\n  -- Optional, set to true if you use the Obsidian Advanced URI plugin.\n  -- https:\u002F\u002Fgithub.com\u002FVinzent03\u002Fobsidian-advanced-uri\n  use_advanced_uri = false,\n\n  -- Optional, set to true to force ':ObsidianOpen' to bring the app to the foreground.\n  open_app_foreground = false,\n\n  picker = {\n    -- Set your preferred picker. Can be one of 'telescope.nvim', 'fzf-lua', or 'mini.pick'.\n    name = \"telescope.nvim\",\n    -- Optional, configure key mappings for the picker. These are the defaults.\n    -- Not all pickers support all mappings.\n    note_mappings = {\n      -- Create a new note from your query.\n      new = \"\u003CC-x>\",\n      -- Insert a link to the selected note.\n      insert_link = \"\u003CC-l>\",\n    },\n    tag_mappings = {\n      -- Add tag(s) to current note.\n      tag_note = \"\u003CC-x>\",\n      -- Insert a tag at the current location.\n      insert_tag = \"\u003CC-l>\",\n    },\n  },\n\n  -- Optional, sort search results by \"path\", \"modified\", \"accessed\", or \"created\".\n  -- The recommend value is \"modified\" and `true` for `sort_reversed`, which means, for example,\n  -- that `:ObsidianQuickSwitch` will show the notes sorted by latest modified time\n  sort_by = \"modified\",\n  sort_reversed = true,\n\n  -- Set the maximum number of lines to read from notes on disk when performing certain searches.\n  search_max_lines = 1000,\n\n  -- Optional, determines how certain commands open notes. The valid options are:\n  -- 1. \"current\" (the default) - to always open in the current window\n  -- 2. \"vsplit\" - to open in a vertical split if there's not already a vertical split\n  -- 3. \"hsplit\" - to open in a horizontal split if there's not already a horizontal split\n  open_notes_in = \"current\",\n\n  -- Optional, define your own callbacks to further customize behavior.\n  callbacks = {\n    -- Runs at the end of `require(\"obsidian\").setup()`.\n    ---@param client obsidian.Client\n    post_setup = function(client) end,\n\n    -- Runs anytime you enter the buffer for a note.\n    ---@param client obsidian.Client\n    ---@param note obsidian.Note\n    enter_note = function(client, note) end,\n\n    -- Runs anytime you leave the buffer for a note.\n    ---@param client obsidian.Client\n    ---@param note obsidian.Note\n    leave_note = function(client, note) end,\n\n    -- Runs right before writing the buffer for a note.\n    ---@param client obsidian.Client\n    ---@param note obsidian.Note\n    pre_write_note = function(client, note) end,\n\n    -- Runs anytime the workspace is set\u002Fchanged.\n    ---@param client obsidian.Client\n    ---@param workspace obsidian.Workspace\n    post_set_workspace = function(client, workspace) end,\n  },\n\n  -- Optional, configure additional syntax highlighting \u002F extmarks.\n  -- This requires you have `conceallevel` set to 1 or 2. See `:help conceallevel` for more details.\n  ui = {\n    enable = true,  -- set to false to disable all additional syntax features\n    update_debounce = 200,  -- update delay after a text change (in milliseconds)\n    max_file_length = 5000,  -- disable UI features for files with more than this many lines\n    -- Define how various check-boxes are displayed\n    checkboxes = {\n      -- NOTE: the 'char' value has to be a single character, and the highlight groups are defined below.\n      [\" \"] = { char = \"󰄱\", hl_group = \"ObsidianTodo\" },\n      [\"x\"] = { char = \"\", hl_group = \"ObsidianDone\" },\n      [\">\"] = { char = \"\", hl_group = \"ObsidianRightArrow\" },\n      [\"~\"] = { char = \"󰰱\", hl_group = \"ObsidianTilde\" },\n      [\"!\"] = { char = \"\", hl_group = \"ObsidianImportant\" },\n      -- Replace the above with this if you don't have a patched font:\n      -- [\" \"] = { char = \"☐\", hl_group = \"ObsidianTodo\" },\n      -- [\"x\"] = { char = \"✔\", hl_group = \"ObsidianDone\" },\n\n      -- You can also add more custom ones...\n    },\n    -- Use bullet marks for non-checkbox lists.\n    bullets = { char = \"•\", hl_group = \"ObsidianBullet\" },\n    external_link_icon = { char = \"\", hl_group = \"ObsidianExtLinkIcon\" },\n    -- Replace the above with this if you don't have a patched font:\n    -- external_link_icon = { char = \"\", hl_group = \"ObsidianExtLinkIcon\" },\n    reference_text = { hl_group = \"ObsidianRefText\" },\n    highlight_text = { hl_group = \"ObsidianHighlightText\" },\n    tags = { hl_group = \"ObsidianTag\" },\n    block_ids = { hl_group = \"ObsidianBlockID\" },\n    hl_groups = {\n      -- The options are passed directly to `vim.api.nvim_set_hl()`. See `:help nvim_set_hl`.\n      ObsidianTodo = { bold = true, fg = \"#f78c6c\" },\n      ObsidianDone = { bold = true, fg = \"#89ddff\" },\n      ObsidianRightArrow = { bold = true, fg = \"#f78c6c\" },\n      ObsidianTilde = { bold = true, fg = \"#ff5370\" },\n      ObsidianImportant = { bold = true, fg = \"#d73128\" },\n      ObsidianBullet = { bold = true, fg = \"#89ddff\" },\n      ObsidianRefText = { underline = true, fg = \"#c792ea\" },\n      ObsidianExtLinkIcon = { fg = \"#c792ea\" },\n      ObsidianTag = { italic = true, fg = \"#89ddff\" },\n      ObsidianBlockID = { italic = true, fg = \"#89ddff\" },\n      ObsidianHighlightText = { bg = \"#75662e\" },\n    },\n  },\n\n  -- Specify how to handle attachments.\n  attachments = {\n    -- The default folder to place images in via `:ObsidianPasteImg`.\n    -- If this is a relative path it will be interpreted as relative to the vault root.\n    -- You can always override this per image by passing a full path to the command instead of just a filename.\n    img_folder = \"assets\u002Fimgs\",  -- This is the default\n\n    -- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`.\n    ---@return string\n    img_name_func = function()\n      -- Prefix image names with timestamp.\n      return string.format(\"%s-\", os.time())\n    end,\n\n    -- A function that determines the text to insert in the note when pasting an image.\n    -- It takes two arguments, the `obsidian.Client` and an `obsidian.Path` to the image file.\n    -- This is the default implementation.\n    ---@param client obsidian.Client\n    ---@param path obsidian.Path the absolute path to the image file\n    ---@return string\n    img_text_func = function(client, path)\n      path = client:vault_relative_path(path) or path\n      return string.format(\"![%s](%s)\", path.name, path)\n    end,\n  },\n}\n```\n\n### Notes on configuration\n\n#### Workspaces\n\nFor most Obsidian users, each workspace you configure in your obsidian.nvim config should correspond to a unique Obsidian vault, in which case the `path` of each workspace should be set to the corresponding vault root path.\n\nFor example, suppose you have an Obsidian vault at `~\u002Fvaults\u002Fpersonal`, then the `workspaces` field in your config would look like this:\n\n```lua\nconfig = {\n  workspaces = {\n    {\n      name = \"personal\",\n      path = \"~\u002Fvaults\u002Fpersonal\",\n    },\n  }\n}\n```\n\nHowever obsidian.nvim's concept of workspaces is a little more general than that of vaults, since it's also valid to configure a workspace that doesn't correspond to a vault, or to configure multiple workspaces for a single vault. The latter case can be useful if you want to segment a single vault into multiple directories with different settings applied to each directory. For example:\n\n```lua\nconfig = {\n  workspaces = {\n    {\n      name = \"project-1\",\n      path = \"~\u002Fvaults\u002Fpersonal\u002Fproject-1\",\n      -- `strict=true` here tells obsidian to use the `path` as the workspace\u002Fvault root,\n      -- even though the actual Obsidian vault root may be `~\u002Fvaults\u002Fpersonal\u002F`.\n      strict = true,\n      overrides = {\n        -- ...\n      },\n    },\n    {\n      name = \"project-2\",\n      path = \"~\u002Fvaults\u002Fpersonal\u002Fproject-2\",\n      strict = true,\n      overrides = {\n        -- ...\n      },\n    },\n  }\n}\n```\n\nobsidian.nvim also supports \"dynamic\" workspaces. These are simply workspaces where the `path` is set to a Lua function (that returns a path) instead of a hard-coded path. This can be useful in several scenarios, such as when you want a workspace whose `path` is always set to the parent directory of the current buffer:\n\n\n```lua\nconfig = {\n  workspaces = {\n    {\n      name = \"buf-parent\",\n      path = function()\n        return assert(vim.fs.dirname(vim.api.nvim_buf_get_name(0)))\n      end,\n    },\n  }\n}\n```\n\nDynamic workspaces are also useful when you want to use a subset of this plugin's functionality on markdown files outside of your \"fixed\" vaults.\nSee [using obsidian.nvim outside of a workspace \u002F Obsidian vault](#usage-outside-of-a-workspace-or-vault).\n\n#### Completion\n\nobsidian.nvim will set itself up as an nvim-cmp source automatically when you enter a markdown buffer within your vault directory, you do **not** need to specify this plugin as a cmp source manually.\n\nNote that in order to trigger completion for tags _within YAML frontmatter_ you still need to type the \"#\" at the start of the tag. obsidian.nvim will remove the \"#\" when you hit enter on the tag completion item.\n\n#### Syntax highlighting\n\nIf you're using [nvim-treesitter](https:\u002F\u002Fgithub.com\u002Fnvim-treesitter\u002Fnvim-treesitter\u002Fblob\u002Fmaster\u002FREADME.md) you're configuration should include both \"markdown\" and \"markdown_inline\" sources:\n\n```lua\nrequire(\"nvim-treesitter.configs\").setup({\n  ensure_installed = { \"markdown\", \"markdown_inline\", ... },\n  highlight = {\n    enable = true,\n  },\n})\n```\n\nIf you use `vim-markdown` you'll probably want to disable its frontmatter syntax highlighting (`vim.g.vim_markdown_frontmatter = 1`) which I've found doesn't work very well.\n\n#### Concealing characters\n\nIf you wish to use the formatting concealment features, you will need to have `conceallevel` set to a value that allows it (either `1` or `2`), for example:\n`set conceallevel=1` in viml or `vim.opt.conceallevel = 1` in a lua config.\n\n#### Note naming and location\n\nThe `notes_subdir` and `note_id_func` options are not mutually exclusive. You can use them both. For example, using a combination of both of the above settings, a new note called \"My new note\" will assigned a path like `notes\u002F1657296016-my-new-note.md`.\n\n#### `gf` passthrough\n\nIf you want the `gf` passthrough functionality but you've already overridden the `gf` keybinding, just change your `gf` mapping definition to something like this:\n\n```lua\nvim.keymap.set(\"n\", \"gf\", function()\n  if require(\"obsidian\").util.cursor_on_markdown_link() then\n    return \"\u003Ccmd>ObsidianFollowLink\u003CCR>\"\n  else\n    return \"gf\"\n  end\nend, { noremap = false, expr = true })\n```\n\nThen make sure to comment out the `gf` keybinding in your obsidian.nvim config:\n\n```lua\nmappings = {\n  -- [\"gf\"] = ...\n},\n```\n\nOr alternatively you could map obsidian.nvim's follow functionality to a different key:\n\n```lua\nmappings = {\n  [\"fo\"] = {\n    action = function()\n      return require(\"obsidian\").util.gf_passthrough()\n    end,\n    opts = { noremap = false, expr = true, buffer = true },\n  },\n},\n```\n\n### Using templates\n\nTo insert a template in the current note, run the command `:ObsidianTemplate`. This will open a list of available templates in your templates folder with your preferred picker. Select a template and hit `\u003CCR>` to insert.\nTo create a new note from a template, run the command `:ObsidianNewFromTemplate`. This will prompt you for an optional path for the new note and will open a list of available templates in your templates folder with your preferred picker. Select a template and hit `\u003CCR>` to create the new note with the selected template.\nSubstitutions for `{{id}}`, `{{title}}`, `{{path}}`, `{{date}}`, and `{{time}}` are supported out-of-the-box.\nFor example, with the following configuration\n\n```lua\n{\n  -- other fields ...\n\n  templates = {\n      folder = \"my-templates-folder\",\n      date_format = \"%Y-%m-%d-%a\",\n      time_format = \"%H:%M\",\n  },\n}\n```\n\nand the file `~\u002Fmy-vault\u002Fmy-templates-folder\u002Fnote template.md`:\n\n```markdown\n# {{title}}\n\nDate created: {{date}}\n```\n\ncreating the note `Configuring Neovim.md` and executing `:ObsidianTemplate` will insert\n\n```markdown\n# Configuring Neovim\n\nDate created: 2023-03-01-Wed\n```\n\nabove the cursor position.\n\nYou can also define custom template substitutions with the configuration field `templates.substitutions`. For example, to automatically substitute the template variable `{{yesterday}}` when inserting a template, you could add this to your config:\n\n```lua\n{\n-- other fields ...\ntemplates = {\n  substitutions = {\n    yesterday = function()\n      return os.date(\"%Y-%m-%d\", os.time() - 86400)\n    end\n  }\n}\n```\n\n### Usage outside of a workspace or vault\n\nIt's possible to configure obsidian.nvim to work on individual markdown files outside of a regular workspace \u002F Obsidian vault by configuring a \"dynamic\" workspace. To do so you just need to add a special workspace with a function for the `path` field (instead of a string), which should return a *parent* directory of the current buffer. This tells obsidian.nvim to use that directory as the workspace `path` and `root` (vault root) when the buffer is not located inside another fixed workspace.\n\nFor example, to extend the configuration above this way:\n\n```diff\n{\n  workspaces = {\n     {\n       name = \"personal\",\n       path = \"~\u002Fvaults\u002Fpersonal\",\n     },\n     ...\n+    {\n+      name = \"no-vault\",\n+      path = function()\n+        -- alternatively use the CWD:\n+        -- return assert(vim.fn.getcwd())\n+        return assert(vim.fs.dirname(vim.api.nvim_buf_get_name(0)))\n+      end,\n+      overrides = {\n+        notes_subdir = vim.NIL,  -- have to use 'vim.NIL' instead of 'nil'\n+        new_notes_location = \"current_dir\",\n+        templates = {\n+          folder = vim.NIL,\n+        },\n+        disable_frontmatter = true,\n+      },\n+    },\n+  },\n   ...\n}\n```\n\nWith this configuration, anytime you enter a markdown buffer outside of \"~\u002Fvaults\u002Fpersonal\" (or whatever your configured fixed vaults are), obsidian.nvim will switch to the dynamic workspace with the path \u002F root set to the parent directory of the buffer.\n\nPlease note that in order to avoid unexpected behavior (like a new directory being created for `notes_subdir`) it's important to carefully set the workspace `overrides` options.\nAnd keep in mind that to reset a configuration option to `nil` you'll have to use `vim.NIL` there instead of the builtin Lua `nil` due to the way Lua tables work.\n\n## Contributing\n\nPlease read the [CONTRIBUTING](https:\u002F\u002Fgithub.com\u002Fepwalsh\u002Fobsidian.nvim\u002Fblob\u002Fmain\u002F.github\u002FCONTRIBUTING.md) guide before submitting a pull request.\n\nAnd if you're feeling especially generous I always appreciate some coffee funds! ❤️\n\n[![BuyMeACoffee](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FBuy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https:\u002F\u002Fwww.buymeacoffee.com\u002Fepwalsh)\n","obsidian.nvim 是一个用于在 Neovim 中编写和浏览 Obsidian 笔记库的插件。它使用 Lua 语言开发，提供了快速异步的笔记引用和标签补全功能，通过集成 nvim-cmp 实现高效编辑体验。此外，该插件还支持命令行操作以及模板使用，增强了用户在 Neovim 环境下管理个人知识库的能力。尽管 obsidian.nvim 并非旨在完全替代官方应用的所有特性（如移动版支持或图形化探索视图），但对于偏好于使用 Neovim 进行文本编辑同时又希望享受 Obsidian 生态优势的开发者来说，这是一个理想的工具。",2,"2026-06-11 03:33:00","high_star"]