emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] feat: add markdown-ts-mode


From: Rahul Martim Juliato
Subject: Re: [PATCH] feat: add markdown-ts-mode
Date: Mon, 22 Apr 2024 22:20:14 -0300
User-agent: Gnus/5.13 (Gnus v5.13)

Philip Kaludercic <philipk@posteo.net> writes:

> Rahul Martim Juliato <rahuljuliato@gmail.com> writes:
>
>> Thanks Eli and Jostein!
>>
>> No problem criticising :)
>>
>>
>> Please find a new patch attached. Things I've made:
>>
>> - changed the file to the textmodes folder
>>
>> - made it inherit from `text-mode'
>>
>> - changed the news with +++
>>
>> - changed `emacs.texi' (is it here?) to add Markdown
>>
>> - scratched my head until 2:30AM thinking why it would not work for
>>   Jostein test.
>>
>>
>> Well Jostein, I've been played by the tree-sitter github repository
>> maintainer, lol.
>>
>> First, a little note. There's actually no major changes to the version
>> on github. I only changed documenting strings and made some small name
>> changes to more "alike" already existing modes.
>>
>> It happens that on tree-sitter repository, unlike any other of their
>> repositories (that I've seen), "main" branch is NOT the current branch,
>> but the "we moved from here bye" one.
>>
>> The current default branch is "split_parser" where
>> tree-sitter-markdown/src/ resides, hence the confusion.
>>
>> So, I wrote the mode with the "main" one in mind.
>>
>> I already checked the "new" (split_parser) one, and it seems it is
>> possible to convert the current work to use this one instead. I'll try
>> to do this in the middle of the week or sooner :)
>>
>> In the mean time, I realized more people would like to test this patch
>> and tree-sitter setup is really trick, so I made this little "guide" on
>> how to apply it until the end result (this might work now, pointing to
>> the "main" branch with the current patch).
>>
>> If you could please try the path (B) on the guide and tell me if this
>> works for you, It would be nice, Jostein.
>>
>>
>> Thanks!
>>
>> Rahul
>>
>>
>>
>> --- beggining of guide on how to apply this patch and test it
>>
>> Git apply this patch.
>>
>> Run the autogen script:
>>
>> ./autogen.sh
>>
>> Make sure configure uses tree-sitter:
>>
>> ./configure --with-tree-sitter
>>
>> Compile:
>>
>> make bootstrap
>>
>> Check the build:
>>
>> ./src/emacs -Q --version
>>
>> Open emacs
>>
>> ./src/emacs -Q --init-dir=~/tmp_emacs_dir/
>>
>>
>> A) The Hard Way
>>
>> Visit a .md file
>>
>> C-x f TEST.md
>>
>> Note the mode will not automatically load.
>>
>> This behavior is the same as typescript-ts-mode or other
>> treesitter modes I've been using.
>>
>> M-x markdown-ts-mode
>>
>> It will fail since you have no tree sitter grammar installed.
>> and will suggest installing it with `treesit-install-language-grammar'.
>>
>> This behaviour is also standard for the tree-sitter modes I
>> currently use (typescript, tsx, rust).
>>
>> Issuing "M-x treesit-install-language-grammar RET".
>>
>> It asks for language, complete with "markdown RET".
>>
>> It says there's no recipie for it, if you want to build it
>> interactivelly. Anwser "yes".
>>
>> It asks for the URL where the grammar is hosted, enter:
>> "https://github.com/tree-sitter-grammars/tree-sitter-markdown RET"
>>
>> It asks for the tag or branch, setting the default, enter "main RET".
>>
>> It asks for the subfolder, leave the default (src), enter "RET".
>>
>> It asks for the C compiler to use (default: auto-detect), just "RET".
>>
>> It asks for the C++ compiler to use (default: auto-detect), just "RET".
>>
>> Install to (default "~/tmp_emacs_dir/treesitter"), just "RET".
>>
>> It will clone the repository, compile the library and tell in the
>> minibuffer the library is installed to your folder.
>>
>>
>> B) The Easier Way.
>>
>> Copy-paste and eval this use-package definition.
>>
>> (use-package markdown-ts-mode
>>   :mode ("\\.md\\'" . markdown-ts-mode)
>>   :defer 't
>>   :config
>>   (add-to-list 'treesit-language-source-alist '(markdown 
>> "https://github.com/tree-sitter-grammars/tree-sitter-markdown"; "main" 
>> "src")))
>>
>>
>> Visit your markdown test file.
>>
>> It will probably fail due to the missing grammar.
>>
>> Issue "M-x treesit-install-language-grammar RET".
>>
>> Now with TAB it should complete "markdown", if not, type it.
>>
>> As we already have the source now defined, just hit "RET" to install
>> to the default treemacs folder.
>>
>> It will clone the repository and say it installed on your folder.
>>
>> Just reload the mode with "M-x markdown-ts-mode".
>>
>> From now on (with the use-package definition on `init.el') you should
>> just open .md and have the highlight and stuff.
>>
>> --- end of the guide
>>
>> From 45796df36129ec77c532b3fa21cdd0b8033c9777 Mon Sep 17 00:00:00 2001
>> From: Rahul Martim Juliato <rahul.juliato@gmail.com>
>> Date: Fri, 19 Apr 2024 23:21:20 -0300
>> Subject: [PATCH] feat: add markdown-ts-mode
>>
>>  * lisp/textmodes/markdown-ts-mode.el: New file.
>>  * doc/emacs/emacs.texi: Add Markdown to the manual
>>  * etc/NEWS: Announce markdown-ts-mode
>> ---
>>  doc/emacs/emacs.texi               |   1 +
>>  etc/NEWS                           |   5 ++
>>  lisp/textmodes/markdown-ts-mode.el | 106 +++++++++++++++++++++++++++++
>>  3 files changed, 112 insertions(+)
>>  create mode 100644 lisp/textmodes/markdown-ts-mode.el
>>
>> diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
>> index 7d77f13ab21..244c822ee04 100644
>> --- a/doc/emacs/emacs.texi
>> +++ b/doc/emacs/emacs.texi
>> @@ -618,6 +618,7 @@ Top
>>  * Enriched Text::       Editing text enriched with fonts, colors, etc.
>>  * Text Based Tables::   Commands for editing text-based tables.
>>  * Two-Column::          Splitting text columns into separate windows.
>> +* Markdown::            Major mode for editing Markdown files.
>>  
>>  Filling Text
>>  
>> diff --git a/etc/NEWS b/etc/NEWS
>> index 8ad1e78ca60..06fbaa03b55 100644
>> --- a/etc/NEWS
>> +++ b/etc/NEWS
>> @@ -1688,6 +1688,11 @@ A major mode based on the tree-sitter library for 
>> editing Elixir files.
>>  *** New major mode 'lua-ts-mode'.
>>  A major mode based on the tree-sitter library for editing Lua files.
>>  
>> ++++
>> +*** New major mode 'markdown-ts-mode'.
>> +A major mode based on the tree-sitter library for editing Markdown files.
>> +
>> +
>>  ** Minibuffer and Completions
>>  
>>  +++
>> diff --git a/lisp/textmodes/markdown-ts-mode.el 
>> b/lisp/textmodes/markdown-ts-mode.el
>> new file mode 100644
>> index 00000000000..063780a772f
>> --- /dev/null
>> +++ b/lisp/textmodes/markdown-ts-mode.el
>> @@ -0,0 +1,106 @@
>> +;;; markdown-ts-mode.el --- tree sitter support for Markdown  -*- 
>> lexical-binding: t; -*-
>> +
>> +;; Copyright (C) 2024 Free Software Foundation, Inc.
>> +
>> +;; Author     : Rahul Martim Juliato <rahul.juliato@gmail.com>
>> +;; Maintainer : Rahul Martim Juliato <rahul.juliato@gmail.com>
>> +;; Created    : April 2024
>> +;; Keywords   : markdown md languages tree-sitter
>> +
>> +;; This file is part of GNU Emacs.
>> +
>> +;; GNU Emacs is free software: you can redistribute it and/or modify
>> +;; it under the terms of the GNU General Public License as published by
>> +;; the Free Software Foundation, either version 3 of the License, or
>> +;; (at your option) any later version.
>> +
>> +;; GNU Emacs is distributed in the hope that it will be useful,
>> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +;; GNU General Public License for more details.
>> +
>> +;; You should have received a copy of the GNU General Public License
>> +;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
>> +
>> +;;; Commentary:
>> +;;
>
> You should probably briefly explain the package here.
>
>> +;;; Code:
>> +
>> +(require 'treesit)
>> +(require 'subr-x)
>> +
>> +(declare-function treesit-node-parent "treesit.c")
>> +(declare-function treesit-node-type "treesit.c")
>> +(declare-function treesit-parser-create "treesit.c")
>> +
>> +(defvar markdown-ts--treesit-settings
>> +  (treesit-font-lock-rules
>> +   :language 'markdown
>> +   :override t
>> +   :feature 'delimiter
>> +   '([ "[" "]" "(" ")" ] @shadow)
>> +
>> +   :language 'markdown
>> +   :feature 'paragraph
>> +   '([((atx_heading) @font-lock-keyword-face)
>> +      ((block_quote_marker) @font-lock-string-face)
>> +      ((code_span) @font-lock-string-face)
>> +      ((emphasis) @underline)
>> +      ((image_description) @link)
>> +      ((indented_code_block) @font-lock-string-face)
>> +      ((link_destination) @font-lock-string-face)
>> +      ((setext_heading) @font-lock-keyword-face)
>> +      ((strong_emphasis) @bold)
>> +      ((thematic_break) @shadow)
>> +      (block_quote (block_quote_marker) @font-lock-string-face)
>> +      (block_quote (paragraph) @font-lock-string-face)
>> +      (fenced_code_block (code_fence_content) @font-lock-string-face)
>> +      (fenced_code_block (fenced_code_block_delimiter) @font-lock-doc-face)
>> +      (inline_link (link_destination) @font-lock-string-face)
>> +      (inline_link (link_text) @link)
>> +      (list_item (list_marker_dot) @font-lock-keyword-face)
>> +      (list_item (list_marker_minus) @font-lock-keyword-face)
>> +      (list_item (list_marker_plus) @font-lock-keyword-face)
>> +      (list_item (list_marker_star) @font-lock-keyword-face)
>> +      (shortcut_link (link_text) @link)
>> +      ])))
>> +
>> +(defun markdown-ts-imenu-node-p (node)
>> +  "Check if NODE is a valid entry to imenu."
>> +  (equal (treesit-node-type (treesit-node-parent node))
>> +         "atx_heading"))
>> +
>> +(defun markdown-ts-imenu-name-function (node)
>> +  "Return an imenu entry if NODE is a valid header."
>> +  (let ((name (treesit-node-text node)))
>> +    (if (markdown-ts-imenu-node-p node)
>> +    (thread-first (treesit-node-parent node)(treesit-node-text))
>> +      name)))
>> +
>> +(defun markdown-ts-setup ()
>> +  "Setup treesit for `markdown-ts-mode'."
>> +  (setq-local treesit-font-lock-settings markdown-ts--treesit-settings)
>> +  (treesit-major-mode-setup))
>> +
>> +;;;###autoload
>> +(define-derived-mode markdown-ts-mode text-mode "Markdown"
>> +  "Major mode for editing Markdown using tree-sitter grammar."
>> +  (setq-local font-lock-defaults nil
>> +          treesit-font-lock-feature-list '((delimiter)
>> +                                           (paragraph)))
>> +
>> +  (setq-local treesit-simple-imenu-settings
>> +              `(("Headings" markdown-ts-imenu-node-p nil 
>> markdown-ts-imenu-name-function)))
>> +
>> +  (when (treesit-ready-p 'markdown)
>> +    (treesit-parser-create 'markdown)
>> +    (markdown-ts-setup)))
>> +
>> +(derived-mode-add-parents 'markdown-ts-mode '(markdown-mode))
>> +
>> +(if (treesit-ready-p 'markdown)
>> +    (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-ts-mode)))
>> +
>> +(provide 'markdown-ts-mode)
>> +;;; markdown-ts-mode.el ends here
>
> So if I understand correctly, there is no keymap or any convenience
> features that markdown-mode provides, because this is just the
> beginning, right?  A large part of major modes for me is not just the
> syntax highlighting and integration into Emacs systems, but also
> bindings that in the case of Markdown would insert links or add/remove
> emphasis.  I think it would be nice, if we could add these features in
> the future, and re-use bindings from a package like AucTeX to build on
> existing intuition (org-mode would be an alternative, but I am not a fan
> or their choice of bindings).  Some commands to "compile" and preview a
> document would also be nice.


Hello there again!

Please find attached the current version of this patch.

It now works with the "official" tree-sitter grammar for markdown:
https://github.com/tree-sitter-grammars/tree-sitter-markdown

Please note (as explained above) the `main branch' is not the default
anymore, but `split_parser' is.

They splitted the parser into two, one for the body of the document and
another to inline.

So, in order to test this patch, configure it with:

(use-package markdown-ts-mode
    :ensure nil
    :defer t  
    :mode ("\\.md\\'" . markdown-ts-mode)
    :config
    (add-to-list 'treesit-language-source-alist '(markdown 
"https://github.com/tree-sitter-grammars/tree-sitter-markdown"; "split_parser" 
"tree-sitter-markdown/src"))
    (add-to-list 'treesit-language-source-alist '(markdown-inline 
"https://github.com/tree-sitter-grammars/tree-sitter-markdown"; "split_parser" 
"tree-sitter-markdown-inline/src")))

If you visit a markdown file treesit issues an error, as always, asking
for the grammars.

Then, install BOTH grammars:

M-x treesit-install-language-grammar RET markdown RET
M-x treesit-install-language-grammar RET markdown-inline RET

Reload the `markdown-ts-mode'.

And everything should be working fine :)


@Philip, thanks for bringing that up! I completely agree with you;
aiming for a fully-featured mode is our long-term objective.

The idea here is to establish a foundation for supporting markdown files
within Emacs, without relying on external packages.

>From there, we can delve into discussions about editing and exporting
features. For instance, we could consider mimicking bindings and prompts
from org-mode, as well as exploring integrations if users opt to also
utilize third-party markdown-mode.

However, simply having the mode built-in reduces friction significantly
for new ideas and collaborations :)

Attachment: 0001-feat-add-markdown-ts-mode.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]