Skip to content

Commit

Permalink
feat(link): implement add, follow, and paste link features
Browse files Browse the repository at this point in the history
  • Loading branch information
tadmccorkle committed Nov 13, 2023
1 parent 3181aff commit 4303a10
Show file tree
Hide file tree
Showing 10 changed files with 737 additions and 10 deletions.
48 changes: 45 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Tools for working with markdown files in Neovim.
- [Inline surround](#inline-surround)
- [Table of contents](#table-of-contents)
- [List editing](#list-editing)
- [Links](#links)
- [*nvim-treesitter* module](#nvim-treesitter-module)

## Features
Expand All @@ -28,6 +29,10 @@ Tools for working with markdown files in Neovim.
- Insert new items
- Auto-number ordered lists
- Toggle task list items (GFM)
- Links
- Add links over vim motions / visual selection
- Follow links under the cursor
- Paste URLs from clipboard over visual selection as links
- [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/) module support

### Planned features
Expand All @@ -37,9 +42,7 @@ Tools for working with markdown files in Neovim.
- Specify list marker type
- Omit section with HTML tag
- Links
- Create links around highlighted text (visual mode)
- Paste link/image from clipboard (visual mode)
- Follow links
- Completion when adding heading and relative file links
- Tables (GFM)
- Formatting
- Insert rows and columns
Expand Down Expand Up @@ -140,6 +143,23 @@ A table of configuration options can optionally be passed to the `setup()` funct
txt = "`",
},
},
link = {
paste = {
enable = true, -- whether to convert URLs to links on paste
},
-- disable all link keymaps by setting mappings field to "false"
-- selectively disable keymaps by setting corresponding field to "false"
mappings = {
add = "gl", -- (string|boolean) add link
follow = "gx", -- (string|boolean) follow link
}
},
-- hook functions allow for overriding or extending default behavior
-- fallback function with default behavior is provided as argument
hooks = {
-- called when following links with `dest` as the link destination
follow_link = nil, -- fun(dest: string, fallback: fun())
},
on_attach = nil, -- (fun(bufnr: integer)) callback when plugin attaches to a buffer
}
```
Expand Down Expand Up @@ -180,6 +200,7 @@ Detailed usage instructions can be found in the help doc (`:h markdown.usage`).
- [Inline Surround](#inline-surround)
- [Table of Contents](#table-of-contents)
- [List Editing](#list-editing)
- [Links](#links)

### Inline surround

Expand Down Expand Up @@ -300,6 +321,27 @@ Most list editing commands are intended to be invoked by custom keymaps (see not

The `:MDTaskToggle` command toggles the task(s) on the current cursor line (normal mode) or under the current visual selection (visual mode).

### Links

- #### Add <!-- omit in toc -->

Links can be added over vim motions in normal and visual mode. Links are only added when the motion is within one inline block (i.e., not over list markers, blank lines, etc.). In normal mode this is done with **gl{motion}** and over a visual selection with **gl**.

- #### Follow <!-- omit in toc -->

Follow links under the cursor in normal mode with **gx**. Supported in-editor navigation:

- `#destination`: headings in the current buffer
- `./destination`: files and directories relative to the current buffer
- `/destination`: files and directories relative to the working directory
- Other absolute path destinations are opened if they exist

URL destinations are opened in the browser.

- #### Paste URLs <!-- omit in toc -->

URLs can be pasted over a visual selection (not a visual block selection) from the system clipboard as markdown links. The visual selection must be contained by one inline block (i.e., conversion to a link will not occur if the visual selection includes blank lines, list markers, etc.).

## *nvim-treesitter* module

<details>
Expand Down
95 changes: 93 additions & 2 deletions doc/markdown.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ CONTENTS *markdown.nvim.contents*
Insert Items ....................... |markdown.lists.insert_item|
Reset Numbering ................ |markdown.lists.reset_numbering|
Toggle Tasks ....................... |markdown.lists.toggle_task|
Links .............................................. |markdown.links|
Add ........................................ |markdown.links.add|
Follow .................................. |markdown.links.follow|
Paste URLs ............................... |markdown.links.paste|
Configuration .................................. |markdown.configuration|

================================================================================
Expand All @@ -38,6 +42,7 @@ USAGE *markdown.usage*
* Inline Surround (|markdown.inline|)
* Table of Contents (|markdown.toc|)
* List Editing (|markdown.lists|)
* Links (|markdown.links|)

--------------------------------------------------------------------------------
INLINE SURROUND *markdown.inline*
Expand Down Expand Up @@ -214,6 +219,41 @@ TOGGLE TASKS *markdown.lists.toggle_task*
:MDTaskToggle Toggles the task(s) on the current cursor line (normal
mode) or under selected lines (visual mode).

--------------------------------------------------------------------------------
LINKS *markdown.links*

Link keymaps are set up after |markdown.nvim| is either configured with a call
to |markdown.setup()| or registered as an |nvim-treesitter| module (see
|markdown.configuration|). |<Plug>| mappings are created regardless of
configuration (see |markdown.plug_mappings|).

ADD *markdown.links.add*

Links can be added over vim motions in normal and visual mode. Links are only
added when the motion is within one inline block (i.e., not over list markers,
blank lines, etc.). In normal mode this is done with *gl{motion}* and over a
visual selection with *gl*.

FOLLOW *markdown.links.follow*

Follow links under the cursor in normal mode with *gx*. The following link
destinations are supported for in-editor navigation:

* `#destination`: Headings in the current buffer
* `./destination`: Files and directories relative to the current buffer
* `/destination`: Files and directories relative to the working directory
* Other absolute path destinations are opened if they exist

Link destination URLs that begin with `https://`, `http://`, and `www.` are
also supported and are opened in the browser.

PASTE URLS *markdown.links.paste*

URLs can be pasted over a visual selection (not a visual block selection) from
the system clipboard as markdown links. The visual selection must be contained
by one inline block (i.e., conversion to a link will not occur if the visual
selection includes blank lines, list markers, etc.).

================================================================================
CONFIGURATION *markdown.configuration*

Expand All @@ -232,14 +272,18 @@ call:
})
<
*markdown.plug_mappings*
The following plug |<Plug>| mappings are used by |markdown.inline| and are
always set up, so they can be used without explicit configuration:
The following plug |<Plug>| mappings are used by |markdown.inline| and
|markdown.link|. They are always set up and can be used without explicit
configuration:
>vim
<Plug>(markdown_toggle_emphasis)
<Plug>(markdown_toggle_emphasis_line)
<Plug>(markdown_toggle_emphasis_visual)
<Plug>(markdown_delete_emphasis)
<Plug>(markdown_change_emphasis)
<Plug>(markdown_add_link)
<Plug>(markdown_add_link_visual)
<Plug>(markdown_follow_link)
<
markdown.setup({opts}) *markdown.setup()*
Both the standalone plugin and |nvim-treesitter| module configurations
Expand Down Expand Up @@ -270,6 +314,18 @@ markdown.setup({opts}) *markdown.setup()*
txt = "`",
},
},
link = {
paste = {
enable = true,
},
mappings = {
add = "gl",
follow = "gx",
},
},
hooks = {
follow_link = nil,
},
on_attach = nil,
})
<
Expand Down Expand Up @@ -331,6 +387,41 @@ markdown.setup({opts}) *markdown.setup()*
* strikethrough: "~~"
* code: "`"

*markdown.config.link.paste*
link.paste: ~
Defines |markdown.links.paste| behavior for pasting URLs from the
clipboard.

Fields:
* enable enables URL-to-link conversion on paste
Default: true

*markdown.config.link.mappings*
link.mappings: ~
Defines |markdown.links| mappings. Mappings can be selectively
disabled by setting the corresponding field to "false". Disable all
link mappings by setting the entire field to "false".

Fields:
* add begins |{motion}| to toggle emphasis
Default: "gl"
See: |markdown.links.add|

* follow follows link under the cursor
Default: "gx"
See: |markdown.links.follow|

*markdown.config.hooks*
hooks: ~
Functions that allow for overriding or extending default behavior.
Fallback function with default behavior is provided as argument.

Fields:
* follow_link called when following links with `dest` as the
link destination
Signature: fun(dest: string, fallback: fun())
Default: nil

*markdown.config.on_attach*
on_attach: ~
Function called when |markdown.nvim| attaches to a buffer. Useful for
Expand Down
67 changes: 62 additions & 5 deletions lua/markdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local ts = vim.treesitter
local OpFunc = require("markdown.opfunc")
local config = require("markdown.config")
local inline = require("markdown.inline")
local link = require("markdown.link")
local list = require("markdown.list")
local notify = require("markdown.notify")
local toc = require("markdown.toc")
Expand Down Expand Up @@ -57,6 +58,33 @@ local function set_keymaps()
silent = true,
desc = "Change emphasis around the cursor",
})
vim.keymap.set(
"n",
"<Plug>(markdown_add_link)",
function()
return OpFunc("markdown.link", "add")
end,
{
expr = true,
silent = true,
desc = "Add link around a motion",
})
vim.keymap.set(
"x",
"<Plug>(markdown_add_link_visual)",
"<Esc>gv<Cmd>lua require'markdown.link'.add_visual()<CR>",
{
silent = true,
desc = "Add link around a visual selection",
})
vim.keymap.set(
"n",
"<Plug>(markdown_follow_link)",
link.follow,
{
silent = true,
desc = "Follow link under the cursor",
})
end

---@type table<integer, { cmds: table, maps: table }>
Expand Down Expand Up @@ -143,6 +171,33 @@ local function setup_usr_keymaps(cfg, bufnr)
desc = "Change emphasis around the cursor",
})
end

if cfg.link.mappings then
set_cached_keymap(
"n",
cfg.link.mappings.add,
"<Plug>(markdown_add_link)",
{
buffer = bufnr,
desc = "Add link around a motion",
})
set_cached_keymap(
"x",
cfg.link.mappings.add,
"<Plug>(markdown_add_link_visual)",
{
buffer = bufnr,
desc = "Add link around a visual selection",
})
set_cached_keymap(
"n",
cfg.link.mappings.follow,
"<Plug>(markdown_follow_link)",
{
buffer = bufnr,
desc = "Follow link under the cursor",
})
end
end

local function check_compat()
Expand All @@ -159,25 +214,27 @@ local function check_compat()
end

local function on_attach(bufnr)
api.nvim_buf_set_var(bufnr, "markdown_nvim_attached", 1)

local cfg = config:get()

setup_usr_cmds(bufnr)
setup_usr_keymaps(cfg, bufnr)

if cfg.link.paste.enable then
link.register_paste_handler()
end

if cfg.on_attach ~= nil then
cfg.on_attach(bufnr)
end
end

local group = api.nvim_create_augroup("markdown.nvim", {})

---@type table<integer, boolean>
local attached = {}

local function on_attach_cb(opts)
if not attached[opts.buf] then
if vim.b.markdown_nvim_attached ~= 1 then
on_attach(opts.buf)
attached[opts.buf] = true
end
end

Expand Down
25 changes: 25 additions & 0 deletions lua/markdown/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@
---@field strikethrough KeyToTxt
---@field code KeyToTxt

---@class LinkMappings
---@field add string|boolean
---@field follow string|boolean

---@class LinkOpts
---@field paste { enable: boolean }
---@field mappings LinkMappings

---@class HookOpts
---@field follow_link fun(dest: string, fallback: fun())|nil

---@class MarkdownConfig
---@field inline_surround InlineSurroundOpts
---@field link LinkOpts
---@field hooks HookOpts
---@field on_attach fun(bufnr: integer)|nil

---@private
Expand Down Expand Up @@ -49,6 +62,18 @@ local default_cfg = {
txt = "`",
},
},
link = {
paste = {
enable = true,
},
mappings = {
add = "gl",
follow = "gx",
},
},
hooks = {
follow_link = nil,
},
on_attach = nil,
}

Expand Down
Loading

0 comments on commit 4303a10

Please sign in to comment.