rustfmt icon indicating copy to clipboard operation
rustfmt copied to clipboard

Format markdown documents containing Rust

Open Michael-F-Bryan opened this issue 7 years ago • 9 comments

I was wanting to do something similar to #1695, although in my case I've got a bunch of markdown files containing Rust snippets which I'd like to format.

I knocked up a quick Python script which almost does this (gist).

However it looks like rustfmt will skip any file not ending in *.rs... Would it be possible to allow non-Rust files if they are explicitly specified using the --file-lines argument?

Output of running rustfmt from Python:

python rustfmt.py 

b"Warning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/codemap.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/lib.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/parse.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/lowering.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/analysis.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/errors.md'\nWarning: Extra file listed in file_lines option '/home/michael/Documents/playground/static-analyser-in-rust/src/lex.md'\n\n"
b''

Michael-F-Bryan avatar Oct 05 '17 15:10 Michael-F-Bryan

Rustfmt formats Rust programs not Rust files - it runs according to the declared module structure. Therefore, running on markdown files might be a little complicated and I'm not sure how to do it. However, it definitely should be possible - it is basically the same idea as testing snippets in markdown.

nrc avatar Oct 06 '17 11:10 nrc

Ah that makes sense given how rustfmt-nightly uses bits of the compiler for parsing and analysis. So the process is a little more complicated than just "here's a string containing some Rust code, please format it".

Would there be any prospects for formatting markdown files or doc-comment examples in the future?

Michael-F-Bryan avatar Oct 06 '17 12:10 Michael-F-Bryan

Would there be any prospects for formatting markdown files or doc-comment examples in the future?

Yeah, it seems like something that it would be good to do and I'm pretty sure it is possible, I'm just not sure how to do it :-)

nrc avatar Oct 07 '17 04:10 nrc

Hi! I'm helping with the translation of TRPL to Brazilian Portuguese (pt-BR) and I'm seeing demand for the same thing. There are many Rust snippets in markdown source that have to be translated, some symbols are translated in batch with search/replace, and it would be nice to run one command to rectify substitutions that have caused formatting mistakes.

Of course this should be super useful to anyone producing Rust content, so the Content Team should be all over this =D Is this the right place to upvote/show support for the feature? Thank you!

hsribei avatar Mar 06 '18 14:03 hsribei

I would like to have this same feature. In my case it's the separate .md doc files that I have that describe the usage of my library. For instance this one: https://github.com/JelteF/derive_more/blob/master/doc/add.md

JelteF avatar Mar 14 '18 20:03 JelteF

I too would like to see a feature like this.

It would help with things like this:

https://github.com/rustic-games/things/commit/ae5280d71af606901354d0f62a9f5fe61a25ddfc

Which uses the (unstable) external_doc feature.

Although, I guess, this would be a bit more complicated, as there are references to modules that only make sense once that external code gets inlined into the main code itself.

Still though, having this would bring this "full circle", allowing you to externally document your library, while still getting proper formatting in those external files.

JeanMertz avatar Nov 14 '18 08:11 JeanMertz

I've been discussing this with @hukkinj1 for Maud: lambda-fairy/maud#231

The conversation is focused on mdformat, which is written in Python. But I can imagine a hypothetical Markdown formatter using pulldown-cmark that does the same thing.

lambda-fairy avatar Jan 15 '21 02:01 lambda-fairy

My quick-and-dirty hack is to:

  1. create a throwaway Cargo project
  2. enable format_code_in_doc_comments in that project
  3. copy the markdown file into the project's lib.rs as documentation for a function
  4. format the library
  5. strip out the documentation comments and function and copy it back to the original file

This seems to work OK.

Script to format markdown
#!/usr/bin/env bash

set -euo pipefail

scratch_dir=$(mktemp -d)
project_dir="${scratch_dir}/scratch"

cargo_toml="${project_dir}/Cargo.toml"
rustfmt_toml="${project_dir}/rustfmt.toml"
lib_rs="${project_dir}/src/lib.rs"

cargo new --lib "${project_dir}"

cat <<-EOF > "${rustfmt_toml}"
format_code_in_doc_comments = true
EOF

for markdown_file in $(git ls-files | rg '.md$'); do
    awk '{ print "/// " $0 } END { print "fn dummy() {}"}' "${markdown_file}" > "${lib_rs}"
    cargo +nightly fmt --manifest-path="${cargo_toml}"
    sed -E -e '$ d' -e 's@/// ?@@' "${lib_rs}" > "${markdown_file}"
done

shepmaster avatar Sep 17 '21 01:09 shepmaster

Also works, doesn't write any files:

cat README.md | (
  while IFS= read -r LINE; do
    if [[ -z ${LINE} ]]; then
      echo "///"
    else
      echo "/// ${LINE}"
    fi
  done
  echo "fn dummy() {}"
) | rustfmt --check --config unstable_features=true,format_code_in_doc_comments=true,max_width=80

Notably rustfmt still returns a zero exit code even if it wants to make changes, so you should check that there is no output if this is somehow part of your CI.

mumbleskates avatar Feb 17 '24 23:02 mumbleskates