markdown.nvim icon indicating copy to clipboard operation
markdown.nvim copied to clipboard

feature: allow using in git COMMIT_EDITMSG files

Open mikavilpas opened this issue 1 year ago • 3 comments
trafficstars

Is your feature request related to a problem? Please describe.

Thanks for this awesome plugin! I use it through lazyvim. I often write my git commit messages in neovim, and fenced code blocks would look nice if they were rendered by this plugin.

Is this possible to configure? I don't have much experience with this.

Describe the solution you'd like

Can we provide some example configuration on how to set this up? I would be fine with maintaining this myself if you would like to keep it out of the plugin repo.

Describe alternatives you've considered

Could also enable this by default, maybe with a config option

Additional information

No response

mikavilpas avatar Aug 21 '24 10:08 mikavilpas

I can get this plugin to work in COMMIT_EDITMSG files by setting :set ft=markdown but that also starts some markdown related LSP servers which I don't really need when working with commit messages.

mikavilpas avatar Aug 21 '24 10:08 mikavilpas

Thank you, I'm glad you're liking it :)

That's a neat idea, I largely write markdown for my own commit messages and don't know why I didn't think to figure this out. It's pretty straightforward, just requires 2 changes and is the same process as adding vimwiki support, plus one extra step due to the LazyVim default configuration.

  1. Add gitcommit to the file_types configuration option of this plugin. I'm not really sure how to modify configurations for plugins configured by LazyVim but just some way to add gitcommit to opts.file_types: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/plugins/extras/lang/markdown.lua#L97

    opts = {
        file_types = { 'markdown', 'norg', 'rmd', 'org', 'gitcommit' },
    }
    
  2. Register markdown as the parser for gitcommit files. This can be done anywhere in your config so long as it runs before this plugin tries to render a file.

    vim.treesitter.language.register('markdown', 'gitcommit')
    
  3. This is the extra step that's LazyVim specific, by default the plugin is set to lazy load on the same file types as provided in opts. You'll need to do a similar change and add gitcommit to ft: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/plugins/extras/lang/markdown.lua#L108

    ft =  { 'markdown', 'norg', 'rmd', 'org', 'gitcommit' },
    

Since we're not modifying the file type to accomplish this it should avoid starting any markdown related LSP servers, though I did not double check this.

I ended up making this change for my own config: https://github.com/MeanderingProgrammer/dotfiles/commit/680bc0a8aed6978a123b7df1007ab88d015ef33f

A couple of other minor things to consider:

  • If you have the gitcommit treesitter parser installed it would probably be a good idea to remove it, since we've registered markdown as the parser it should be unused
  • Commit messages do not follow markdown syntax, I believe any invalid syntax will essentially be skipped over and this plugin should render anything that looks like markdown but it won't be perfect

[!NOTE] In case you're wondering why are there 2 identical lists?

ft is for lazy.nvim to determine when to lazy load this plugin. If lazy.nvim didn't have the list it would load this plugin on startup. I personally don't recommend lazy loading this plugin because of this redundancy and the relatively low startup time of this plugin, but it's not really a problem.

opts.file_types is for this plugin, once loaded, to know what files to run on. If this plugin didn't have a list of file types it would try to run on every file after it is loaded, which would add a lot of overhead since this plugin attaches many event listeners to these buffers.

Since sharing information between a plugin and plugin manager is in no way standardized there's not really a way to have it only defined in one place, other than using a local variable in your config of course.

MeanderingProgrammer avatar Aug 21 '24 19:08 MeanderingProgrammer

In case you want to set different configuration values for commit files I pushed a change to allow overrides based on filetype here: https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/952b1c077a5967f91228f57a6a4979f86386f3c4.

So to disable headings in gitcommit files (just as an example) you would do:

opts = {
    ...
    overrides = {
        filetype = {
            gitcommit = { heading = { enabled = false } },
        },
    },
}

MeanderingProgrammer avatar Aug 21 '24 20:08 MeanderingProgrammer

Wow this solution is incredible! Huge thanks.

image

https://github.com/mikavilpas/dotfiles/commit/ed18a16df5df32501788294bfb04a9fc67687e80

In my image you can see the full diff at the bottom - it's there for github copilot to get some context when suggesting what to write in the commit message. I never read it and don't really care if it's not highlighted 🙂

mikavilpas avatar Aug 22 '24 05:08 mikavilpas

Sweet, no problem :)

I looked at your change and removing the heading isn't strictly necessary, though likely a good idea if you use the default # comment character. You can also change it to something else, I use ;, in your git config:

[core]
    commentChar = ";"

Then re-enable headings.

Huh, I've not seen the putting the diff in the commit approach before, make sense. Depending on how that diff gets there if you have any control over it, surrounding it with a code block using the diff language will make it look nicer:

```diff
<contents_of_diff>
```

Assuming you have the diff parser installed.

MeanderingProgrammer avatar Aug 22 '24 06:08 MeanderingProgrammer

I didn't know core.commentChar exists. This is very nice - now even headings work :)

I'm sure the diff highlighting could be made to work with a prepare-commit-msg git hook, but I think it would be better to somehow get the markdown and gitcommit treesitter parsers to work together.

I might look into this later, I should learn a bit more about how the parsers work.

mikavilpas avatar Aug 22 '24 07:08 mikavilpas

I got a version of this that's almost perfect, however doesn't support the custom core.commentChar, so you'll need to remove that for this to work. Naturally that means headings won't work either.

Instead of parsing the entire commit as markdown using: vim.treesitter.language.register('markdown', 'gitcommit'), we can inject markdown into the message body. So remove that line from the config.

Then install the gitcommit parser: :TSInstall gitcommit.

Finally extending the gitcommit injections to parse the message body only as markdown. To do this add a file named after/queries/gitcommit/injections.scm with the following content:

;extends

((message) @injection.content
  (#set! injection.combined)
  (#set! injection.include-children)
  (#set! injection.language "markdown"))

This will use the parser to highlight the main commit message, comments and diff with --verbose nicely, as well as triggering this plugin to handle the main message body.

The core.commentChar limitation comes from the gitcommit parser itself since it finds comments based on the hard coded # default, there's an issue open for this: https://github.com/gbprod/tree-sitter-gitcommit/issues/45.

Even with a custom core.commentChar it doesn't look worse so I changed to this approach myself: https://github.com/MeanderingProgrammer/dotfiles/commit/17d396ea980ea6a6d61db1b4be32a18240e70411

MeanderingProgrammer avatar Aug 27 '24 09:08 MeanderingProgrammer

Wow this solution is amazing! For now I think I can work around the limitations of core.commentChar by using === under headings (the alternate markdown heading syntax.

I think this is a really cool feature. Have you thought about including it in the plugin?

mikavilpas avatar Aug 27 '24 16:08 mikavilpas

Do you mean adding details about enabling the plugin for commit messages or support for the alternate markdown heading syntax?

MeanderingProgrammer avatar Aug 27 '24 17:08 MeanderingProgrammer

I mean, is it possible to simplify the setup for using render-markdown.nvim in gitcommit buffers, and make it a more "batteries included" experience within render-markdown.nvim for example?

To be honest, I don't know if plugins can add treesitter injections. I feel like this is one of those "it's clearly better to have this" features, and got a bit excited. 😄

mikavilpas avatar Aug 27 '24 18:08 mikavilpas

Ah, gotcha. I'll look into it and see. Similarly I have no idea if a plugin can define injections programatically. Worst case I'll add some documentation, best case I can add some default injections based on filetype and allow users to opt out and define their own.

MeanderingProgrammer avatar Aug 27 '24 21:08 MeanderingProgrammer

I've implemented a batteries included approach here: https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/5ff9a598622422100280769147ad5feff411c6da

Takes care of setting injections using vim.treesitter.query.set, completely configurable on the user side with a default for gitcommit. Currently the only one, will expand it as things come up.

With this you can remove the after/queries/gitcommit/injections.scm file. So now the only things that are needed are the gitcommit treesitter parser and adding gitcommit to the plugin file_types config.

Since this does happen as part of the plugin's configuration lazy loading the plugin could cause problems in that the injection will be added after the buffer loads. So if it doesn't work I would suggest disabling lazy loading and giving that a try.

Thanks for the suggestion, I personally like it as well!

MeanderingProgrammer avatar Aug 28 '24 01:08 MeanderingProgrammer

I can confirm it works nicely. 👍🏻 No issues with lazy loading have come up either.

mikavilpas avatar Aug 28 '24 05:08 mikavilpas