From 0783fe70580f895c5b09cb39014e73bb55db8146 Mon Sep 17 00:00:00 2001 From: AlphaJack Date: Mon, 29 Jan 2024 17:53:47 +0100 Subject: [PATCH] add: support for rstudio foldable sections test: added check for missing reference file --- README.md | 3 - USAGE.md | 107 ++++++++++++++---- tests/input/bash_vim_modeline.sh | 9 ++ tests/input/markdown_empty_first_line.md | 4 - tests/input/r_simple.R | 16 +++ tests/reference/bash_vim_modeline.sh | 22 ++++ ...hon_broken.toc.py => python_broken_toc.py} | 0 tests/reference/r_simple.R | 26 +++++ tests/test_toc.py | 10 +- toc/toc.py | 36 +++--- 10 files changed, 190 insertions(+), 43 deletions(-) create mode 100644 tests/input/bash_vim_modeline.sh delete mode 100644 tests/input/markdown_empty_first_line.md create mode 100644 tests/input/r_simple.R create mode 100644 tests/reference/bash_vim_modeline.sh rename tests/reference/{python_broken.toc.py => python_broken_toc.py} (100%) create mode 100644 tests/reference/r_simple.R diff --git a/README.md b/README.md index 7fbebba..8d8859a 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,3 @@ If you have a suggestion or you found a bug, you can use GitHub [issues](https:/ See [CHANGELOG.md](./CHANGELOG.md) -[^1]: No, not really, it's just a match-case statement using the file extension, defaulting to "#" -[^2]: Not even, it's just a bunch of if-else and try-excepts statement that may prevent catastrophic damage -[^3]: The outdated toc to be replaced is defined as the the first match of a non-greedy regex diff --git a/USAGE.md b/USAGE.md index 4a18b69..9687e20 100644 --- a/USAGE.md +++ b/USAGE.md @@ -18,33 +18,50 @@ // │ │ ├── Markdown // │ │ ├── Beancount // │ │ └── Perl -// │ └──┐Wrap around comments needed -// │ ├── CSS -// │ ├── HTML -// │ └── OCaml +// │ ├──┐Wrap around comments needed +// │ │ ├── CSS +// │ │ ├── HTML and Quarto +// │ │ └── OCaml +// │ └──┐Compatibility with third-party editors +// │ ├── Vim and Emacs +// │ └── RStudio +// ├── ################################################################ First section ---- +// ├── text 1 +// ├── ################################ Second section #### +// ├── text 2 +// ├── ################################ Third section ==== // │ // └─────────────────────────────────────────────────────────────── --> # Detailed TOC usage -The scenarios below show different features. +The scenarios below show different features of `toc` + + - [Detailed TOC usage](#detailed-toc-usage) - - [Read the table of contents](#read-the-table-of-contents) - - [Embed the table of contents in the original file](#embed-the-table-of-contents-in-the-original-file) - - [Set a custom comment character](#set-a-custom-comment-character) - - [Show line numbers](#show-line-numbers) - - [Process multiple files](#process-multiple-files) - - [Exceptional file types](#exceptional-file-types) - - [No comments needed](#no-comments-needed) + * [Read the table of contents](#read-the-table-of-contents) + * [Embed the table of contents in the original file](#embed-the-table-of-contents-in-the-original-file) + * [Process multiple files](#process-multiple-files) + * [Show line numbers](#show-line-numbers) + * [Set a custom comment character](#set-a-custom-comment-character) + * [Redirect output to another file](#redirect-output-to-another-file) + * [Other commands](#other-commands) + * [Exceptional file types](#exceptional-file-types) + + [No comments needed](#no-comments-needed) - [Markdown](#markdown) - [Beancount](#beancount) - [Perl](#perl) - - [Wrap around comments needed](#wrap-around-comments-needed) + + [Wrap around comments needed](#wrap-around-comments-needed) - [CSS](#css) - - [HTML](#html) + - [HTML and Quarto](#html-and-quarto) - [OCaml](#ocaml) + + [Compatibility with third-party editors](#compatibility-with-third-party-editors) + - [Vim and Emacs](#vim-and-emacs) + - [RStudio](#rstudio) + + ## Read the table of contents @@ -79,7 +96,17 @@ let Section5 = "Write //, 4 hash characters and the name of section" If you run `toc example.js`, the program will output the following (stdout): ```js - +// ┌───────────────────────────────────────────────────────────────┐ +// │ Contents of example.js │ +// ├───────────────────────────────────────────────────────────────┘ +// │ +// ├──┐Main section +// │ └──┐Nested section +// │ └──┐Nested section +// │ └──┐Nested section +// │ └── Nested section +// │ +// └─────────────────────────────────────────────────────────────── ``` ## Embed the table of contents in the original file @@ -252,7 +279,7 @@ If you feel brave enough, you can run `toc *` over your entire code base, as its For very long files, it may come in handy to run `toc -n example.js` to see the line number of each section, similar to the page numbers in the table of contents of a book: -``` +```js // ┌───────────────────────────────────────────────────────────────┐ // │ Contents of example.js │ // ├───────────────────────────────────────────────────────────────┘ @@ -303,10 +330,10 @@ For Markdown files, you don't need to write comments, just organize your section For [Beancount](https://raw.githubusercontent.com/beancount/beancount/master/examples/example.beancount) files, it's the same for Markdown, but you use `*` instead: -```beancount +```ini * Options -; text +; comment * Transactions ** FY2020 @@ -370,9 +397,9 @@ For CSS files, you have to wrap your `//` comments between `/*` and `*/`: -#### HTML +#### HTML and Quarto -For HTML files, you have to wrap your `//` comments between ``: +For HTML and Quarto files, you have to wrap your `//` comments between ``:
Click to view `example.html` @@ -418,3 +445,43 @@ let () = print_endline "Hello, World!" ```
+ + +### Compatibility with third-party editors + +#### Vim and Emacs + +If you place your Vim Modeline / Emacs mode as the first line, the toc will be appended after + + +#### RStudio + +If you are using RStudio, you may want to end your comments with at least 4 `-`, `=` or `#`. +This marks the comment as a foldable sections: + +
+ Click to view `example.R` + +```r +# ################################################################ Foldable section 1 ---- + +print("Collapse me!") + +# ################################ Foldable section 2 #### + +print("Collapse me!") + +# ################################ Foldable section 3 ==== + +print("Collapse me!") +``` + +
+ + + + + +[^1]: No, not really, it's just a match-case statement using the file extension, defaulting to "#" +[^2]: Not even, it's just a bunch of if-else and try-excepts statement that may prevent catastrophic damage +[^3]: The outdated toc to be replaced is defined as the the first match of a non-greedy regex diff --git a/tests/input/bash_vim_modeline.sh b/tests/input/bash_vim_modeline.sh new file mode 100644 index 0000000..25fe3fd --- /dev/null +++ b/tests/input/bash_vim_modeline.sh @@ -0,0 +1,9 @@ +# vim:set ts=4 sw=4 ft=sh et: + +# ################################################################ Nested 1 +# ################################ Nested 2 +# ################ Nested 3 +# ######## Nested 4 +# #### Nested 5 +# ## Nested 6 +echo "OK" diff --git a/tests/input/markdown_empty_first_line.md b/tests/input/markdown_empty_first_line.md deleted file mode 100644 index 84c8c0f..0000000 --- a/tests/input/markdown_empty_first_line.md +++ /dev/null @@ -1,4 +0,0 @@ - -# Markdown with empty first line - -A small toc should be placed before first heading diff --git a/tests/input/r_simple.R b/tests/input/r_simple.R new file mode 100644 index 0000000..3f2aede --- /dev/null +++ b/tests/input/r_simple.R @@ -0,0 +1,16 @@ +# ################################################################ Head 1 #### + +# test + +# ################################ Head 2 ==== + +# test + +# ################ Head 3 ---- + +# test + +## ################ Invalid ---- + + +# \ No newline at end of file diff --git a/tests/reference/bash_vim_modeline.sh b/tests/reference/bash_vim_modeline.sh new file mode 100644 index 0000000..88fbabe --- /dev/null +++ b/tests/reference/bash_vim_modeline.sh @@ -0,0 +1,22 @@ +# vim:set ts=4 sw=4 ft=sh et: + +# ┌───────────────────────────────────────────────────────────────┐ +# │ Contents of bash_vim_modeline.sh │ +# ├───────────────────────────────────────────────────────────────┘ +# │ +# ├──┐Nested 1 +# │ └──┐Nested 2 +# │ └──┐Nested 3 +# │ └──┐Nested 4 +# │ └──┐Nested 5 +# │ └── Nested 6 +# │ +# └─────────────────────────────────────────────────────────────── + +# ################################################################ Nested 1 +# ################################ Nested 2 +# ################ Nested 3 +# ######## Nested 4 +# #### Nested 5 +# ## Nested 6 +echo "OK" diff --git a/tests/reference/python_broken.toc.py b/tests/reference/python_broken_toc.py similarity index 100% rename from tests/reference/python_broken.toc.py rename to tests/reference/python_broken_toc.py diff --git a/tests/reference/r_simple.R b/tests/reference/r_simple.R new file mode 100644 index 0000000..2e7404d --- /dev/null +++ b/tests/reference/r_simple.R @@ -0,0 +1,26 @@ +# ┌───────────────────────────────────────────────────────────────┐ +# │ Contents of r_simple.R │ +# ├───────────────────────────────────────────────────────────────┘ +# │ +# ├──┐Head 1 +# │ └──┐Head 2 +# │ └── Head 3 +# │ +# └─────────────────────────────────────────────────────────────── + +# ################################################################ Head 1 #### + +# test + +# ################################ Head 2 ==== + +# test + +# ################ Head 3 ---- + +# test + +## ################ Invalid ---- + + +# \ No newline at end of file diff --git a/tests/test_toc.py b/tests/test_toc.py index 7a55a52..62fb89c 100644 --- a/tests/test_toc.py +++ b/tests/test_toc.py @@ -107,15 +107,19 @@ def test_input_files(self): output_content, reference_content = output.read(), reference.read() comparison = True if output_content == reference_content else False with self.subTest(comparison=comparison): - self.assertTrue(comparison, f'Unexpected output processing "{file.name}", please check "{self.output_dir}"') + self.assertTrue(comparison, f'Unexpected content (should be different) processing "{file.name}", please check "{self.output_dir}"') + elif output_file.is_file(): + comparison = False + with self.subTest(comparison=comparison): + self.assertTrue(comparison, f'Unexpected output file (should be none) processing "{file.name}", please check "{self.output_dir}"') elif reference_file.is_file(): comparison = False with self.subTest(comparison=comparison): - self.assertTrue(comparison, f'Unexpected empty output processing "{file.name}", please check "{self.output_dir}"') + self.assertTrue(comparison, f'Unexpected empty output (should be something) processing "{file.name}", please check "{self.output_dir}"') else: comparison = True with self.subTest(comparison=comparison): - self.assertTrue(comparison, f'Expected empty output processing "{file.name}"') + self.assertTrue(comparison, f'Expected empty output (ok) processing "{file.name}"') # @classmethod # def tearDownClass(cls): diff --git a/toc/toc.py b/toc/toc.py index 12d6017..171e9c6 100644 --- a/toc/toc.py +++ b/toc/toc.py @@ -59,7 +59,7 @@ def __init__(self, input: str = "", output=None, lineNumbers: bool = False, char def set_character(self): # automatically select the comment type from its extension, if not already set match self.extension: - case "c" | "carbon" | "cc" | "coffee" | "cpp" | "cs" | "css" | "d" | "dart" | "go" | "h" | "hpp" | "htm" | "html" | "hxx" | "java" | "js" | "kt" | "md" | "pas" | "php" | "pp" | "proto" | "qs" | "rs" | "scala" | "sc" | "swift" | "ts" | "typ" | "xml" | "zig": + case "c" | "carbon" | "cc" | "coffee" | "cpp" | "cs" | "css" | "d" | "dart" | "go" | "h" | "hpp" | "htm" | "html" | "hxx" | "java" | "js" | "kt" | "md" | "pas" | "php" | "pp" | "proto" | "qmd" | "qs" | "rs" | "scala" | "sc" | "swift" | "ts" | "typ" | "xml" | "zig": self.character = "//" case "ahk" | "asm" | "beancount" | "cl" | "clj" | "cljs" | "cljc" | "edn" | "fasl" | "ini" | "lisp" | "lsp" | "rkt" | "scm" | "ss": self.character = ";" @@ -251,7 +251,7 @@ def _toc_header(self): match self.extension: case "css": _tocPrefix = "/*" - case "html" | "md" | "xml": + case "html" | "xml" | "md" | "qmd" | "rmd": _tocPrefix = "" case "ml" | "mli" | "scpd" | "scpt": _tocSuffix = "*)"