Marksman Language Server

repository·main·Indexed 25 days ago

https://github.com/artempyanykh/marksman

A Language Server (LSP) providing code intelligence for Markdown documents. It supports standard Markdown links and Zettelkasten-style wiki-links, offering features such as auto-completion, goto definition, find references, rename refactoring, and diagnostics for broken links or ambiguous headings. Marksman integrates with editors like Zed, Emacs (via lsp-mode or Eglot), and Vim.

Tokens
2K
Snippets
6
Records
17
Agent score
85%

What's inside Marksman

  1. Overview of Marksman features

    main

    Marksman is a Language Server (LSP) that provides code intelligence for Markdown files. It supports standard Markdown links and wiki-link style references (Zettelkasten-style).

    Key features include:

    • Completion: Auto-completion for links and references.
    • Navigation: Goto definition and find references for links.
    • Refactoring: Rename refactoring for links.
    • Diagnostics: Detection of broken wiki-links and duplicate/ambiguous headings.
    • Hover: Information on hover for links.

    Supported link types:

    • Markdown inline links: [text](/path/to/file.md#heading) or [text](#heading).
    • Markdown reference links: `[text]

    [text]: /url "Title"`.

    • Wiki-links: [[another-note]], [[another-note#heading]], or [[#a-heading]].
  2. Use wiki-style links

    main
    Marksman supports wiki-style links (e.g., [[some-doc]] or [[#some-heading]]) alongside standard Markdown links. This is useful for Zettelkasten-style note-taking. Documents can be referenced by either their title or their filename, depending on your configuration.
  3. Set up a Marksman project root

    main

    Marksman works best in a project/workspace context rather than in single-file mode. If you are not seeing cross-file language assistance, ensure a project root is defined. A root is typically identified by:

    1. The root of a Version Control System (VCS) repository.
    2. A folder containing a .marksman.toml marker file.

    If cross-file features are missing, try checking your files into version control or creating a .marksman.toml at your project's root folder.

  4. Configure Marksman settings at user and project levels

    main

    Marksman allows you to customize behavior using two levels of configuration. Settings defined in a project-level configuration file take precedence over user-level settings, which in turn take precedence over global defaults.

    User-level configuration

    Place your config.toml file in the following directory based on your operating system:

    • Linux: $HOME/.config/marksman/config.toml
    • macOS: $HOME/Library/Application Support/marksman/config.toml
    • Windows: $HOME\AppData\Roaming\marksman\config.toml

    Project-level configuration

    Place a .marksman.toml file in the root folder of your project to apply settings specifically to that project.

    Note: You only need to specify the options you wish to override. Do not include all available options in your configuration files.

  5. Configure Marksman for Emacs (LSP Mode or Eglot)

    main

    Marksman can be integrated into Emacs using either lsp-mode or eglot.

    Using LSP Mode (with use-package):

    (use-package markdown-mode
      :hook (markdown-mode . lsp)
      :config
      (require 'lsp-marksman))

    Using Eglot: Add the following to your init.el:

    (add-to-list 'eglot-server-programs '(markdown-mode . ("marksman")))
    (add-hook 'markdown-mode-hook #'eglot-ensure)
    // LSP Mode example
    (use-package markdown-mode
      :hook (markdown-mode . lsp)
      :config
      (require 'lsp-marksman))
    
    // Eglot example
    (add-to-list 'eglot-server-programs '(markdown-mode . ("marksman")))
    (add-hook 'markdown-mode-hook #'eglot-ensure)
  6. Install Marksman using pre-built binaries

    main

    Download the appropriate binary for your OS from the Releases page, then follow these steps to prepare and install it:

    1. Rename and make executable:
      • MacOS: mv marksman-macos marksman && chmod +x marksman
      • Linux: mv marksman-linux marksman && chmod +x marksman
      • Windows: Rename marksman-windows.exe to marksman.exe.
    2. Place in PATH: Move the binary to a directory in your PATH. XDG recommends $HOME/.local/bin/.

    MacOS Security Bypass: If MacOS prevents the binary from opening due to security checks, run: xattr -d com.apple.quarantine <path-to-marksman-bin>

  7. Configure Marksman for Vim (using lsp)

    main

    If using the lsp plugin in Vim, add the following configuration to your ~/.vim/after/ftplugin/markdown.vim file. Ensure you replace /path/to/marksman with the actual path to your Marksman binary.

    if exists('g:loaded_lsp')
      call LspAddServer([#{ name: 'marksman', filetype: ['markdown'], path: '/path/to/marksman', args: ['server'], syncInit: v:true }])
    end
  8. Build Marksman from source

    main

    To build Marksman from the source code, ensure you have the Dotnet SDK installed for your OS, then execute the following commands:

    1. Clone the repository.
    2. Run make install inside the marksman folder.

    The binary will be installed under $HOME/.local/bin (ensure this folder is in your PATH).

    git clone https://github.com/artempyanykh/marksman.git
    cd marksman
    make install
  9. Configure document titles from headings

    main

    By default, Marksman treats the Level 1 heading (# Heading) as the document's title. This assumes a document has at most one Level 1 heading. You can disable this behavior in your .marksman.toml file. Note that disabling this automatically changes the default completion style to a file-based one.

    [core]
    title_from_heading = false
  10. Configure wiki link completion style

    main

    You can control whether wiki links prefer using a document's title or its filename by configuring the completion.wiki.style setting. This setting also affects how refactorings (like renaming) behave:

    • title-slug style: Renaming a file (e.g., foo.md to bar.md) will not update a link like [[foo]] because it is bound to the title. However, renaming the heading # Foo to # Bar will update [[foo]] to [[bar]].
    • file-stem style: The behavior is reversed; renaming the file will update the link, but renaming the heading will not.