From 3ffc68c003666ccb6cf4e636b1f46fbb76b1aa34 Mon Sep 17 00:00:00 2001 From: Geoff Cheshire Date: Sun, 10 May 2026 17:05:41 -0400 Subject: [PATCH] feat: add markdown opt-in extra + fix local.lua load order Adds lua/whipsmart/plugins/markdown.lua as an opt-in extra that bundles render-markdown.nvim (unconditional) and obsidian.nvim + blink.compat (gated on vim.g.obsidian_vaults being set in local.lua). Uses blink.cmp.config.merge_with to extend the completion config post-setup with markdown-specific per_filetype sources and [[wikilink trigger behaviour. Also fixes a load-order bug where pcall(require, 'local') ran before vim.g.have_nerd_font and all vim.o.* defaults were set, making it impossible for local.lua to override them. The call is now at the end of Section 1 so local.lua runs last and overrides work correctly. UNIFIED.md updated: markdown extra documented, roci migration and load-order fix checked off the roadmap. --- UNIFIED.md | 15 +++++- init.lua | 11 ++-- lua/whipsmart/plugins/markdown.lua | 84 ++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 lua/whipsmart/plugins/markdown.lua diff --git a/UNIFIED.md b/UNIFIED.md index a214b663..8cadf4fc 100644 --- a/UNIFIED.md +++ b/UNIFIED.md @@ -31,7 +31,17 @@ require 'whipsmart.plugins.debug' ``` Available extras: `autopairs`, `debug` (DAP/Go), `gitsigns` (extended keymaps), -`indent_line`, `lint`, `neo-tree`. +`indent_line`, `lint`, `markdown` (render-markdown + obsidian), `neo-tree`. + +The `markdown` extra reads `vim.g.obsidian_vaults` from `local.lua` to configure +obsidian.nvim; render-markdown loads unconditionally. Example `local.lua` snippet: +```lua +vim.g.obsidian_vaults = { { name = 'personal', path = '~/Obsidian/Main' } } +``` +Then activate in `lua/custom/plugins/markdown.lua`: +```lua +require 'whipsmart.plugins.markdown' +``` ## 💻 Per-Machine Local Config Each machine maintains a `lua/local.lua` that is **gitignored** and never committed. @@ -60,6 +70,9 @@ cp ~/.config/nvim/lua/local.lua.example ~/.config/nvim/lua/local.lua - [x] Document LSP server setup and opt-in extras workflow. - [x] Replace hostname detection with gitignored lua/local.lua per-machine overrides. - [x] Port hecate config: LSP servers, formatters, treesitter parsers, custom plugins. +- [x] Fix `local.lua` load order — `pcall(require, 'local')` moved to end of Section 1 so it can override defaults. +- [x] Add markdown opt-in extra (render-markdown, obsidian, blink.compat). +- [x] Migrate roci to whipsmart. - [ ] Migrate vera and tau to whipsmart (create their lua/local.lua files). - [ ] Add machine-specific UI toggles for terminal vs. GUI Neovim (via local.lua). - [ ] Centralize snippet collections. diff --git a/init.lua b/init.lua index 6cc720ac..23a01db0 100644 --- a/init.lua +++ b/init.lua @@ -47,11 +47,6 @@ do vim.g.mapleader = ' ' vim.g.maplocalleader = ' ' - -- [[ Machine Specific Setup ]] - -- lua/local.lua is gitignored — each machine maintains its own copy. - -- See lua/local.lua.example for available options. - pcall(require, 'local') - -- Set to true if you have a Nerd Font installed and selected in the terminal vim.g.have_nerd_font = true @@ -118,6 +113,12 @@ do group = vim.api.nvim_create_augroup('whipsmart-highlight-yank', { clear = true }), callback = function() vim.hl.on_yank() end, }) + + -- [[ Machine Specific Setup ]] + -- lua/local.lua is gitignored — each machine maintains its own copy. + -- Loaded last so it can override any default set above. + -- See lua/local.lua.example for available options. + pcall(require, 'local') end -- ============================================================ diff --git a/lua/whipsmart/plugins/markdown.lua b/lua/whipsmart/plugins/markdown.lua new file mode 100644 index 00000000..11d04225 --- /dev/null +++ b/lua/whipsmart/plugins/markdown.lua @@ -0,0 +1,84 @@ +local function gh(repo) return 'https://github.com/' .. repo end + +-- ── render-markdown (always loaded) ───────────────────────────────────────── +vim.pack.add { + gh 'MeanderingProgrammer/render-markdown.nvim', + gh 'nvim-treesitter/nvim-treesitter', +} + +require('render-markdown').setup { + render_modes = { 'n', 'c' }, + heading = { enabled = true }, + bullet = { enabled = true }, + checkbox = { enabled = true }, + code = { enabled = true }, +} + +vim.api.nvim_create_autocmd('FileType', { + desc = 'Markdown editing options', + group = vim.api.nvim_create_augroup('whipsmart-markdown', { clear = true }), + pattern = 'markdown', + callback = function() + vim.opt_local.wrap = true + vim.opt_local.linebreak = true + vim.opt_local.spell = true + vim.opt_local.spelllang = 'en_us' + vim.opt_local.conceallevel = 2 + end, +}) + +-- ── obsidian (opt-in — requires vim.g.obsidian_vaults to be set in local.lua) ─ +-- Example local.lua entry: +-- vim.g.obsidian_vaults = { { name = 'personal', path = '~/Obsidian/Main' } } +if not vim.g.obsidian_vaults then return end + +-- blink.compat must be unversioned (HEAD) — released tags lack cmp.get_config() +vim.pack.add { + { src = gh 'epwalsh/obsidian.nvim', version = vim.version.range '*' }, + gh 'nvim-lua/plenary.nvim', + gh 'saghen/blink.compat', +} + +require('blink.compat').setup {} + +require('obsidian').setup { + workspaces = vim.g.obsidian_vaults, + completion = { nvim_cmp = false, min_chars = 2 }, +} + +-- Register obsidian nvim-cmp sources via blink.compat shim +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()) + +-- Extend blink.cmp config post-setup via the v1 merge_with API. +-- Called from custom/plugins/ (Section 3), so plugins.cmp has already run setup(). +require('blink.cmp.config').merge_with { + completion = { + trigger = { + -- Remove '[' so [[ wikilinks trigger the completion menu + show_on_x_blocked_trigger_characters = { "'", '"', '(', '{' }, + }, + menu = { + -- Suppress auto-popup in markdown/text except when '[' was the trigger + auto_show = function(ctx) + if vim.tbl_contains({ 'markdown', 'text' }, vim.bo.filetype) then + return ctx.trigger.initial_kind == 'trigger_character' + and ctx.trigger.initial_character == '[' + end + return true + end, + }, + }, + sources = { + per_filetype = { + markdown = { 'obsidian', 'obsidian_new', 'obsidian_tags', 'lsp', 'path', 'snippets', 'buffer' }, + }, + 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' }, + }, + }, +}