Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shorter syntax for common use cases #2

Open
jannismain opened this issue Jul 25, 2023 · 3 comments
Open

Shorter syntax for common use cases #2

jannismain opened this issue Jul 25, 2023 · 3 comments

Comments

@jannismain
Copy link
Owner

jannismain commented Jul 25, 2023

Jinja macros are different from regular Python code, in that they are mainly used in files of another type (e.g. calling a Jinja macro from Markdown). Therefore, the editor cannot provide typical affordances, such as autocomplete, inline documentation, etc.:

  • no autocomplete -> all arguments have to be typed
  • no docstrings during typing -> arguments have to be remembered or referenced
  • always on single lines -> long and terse expressions

This leads to different trade-offs when designing functions to be used primarily in a Jinja template:

  • favor short and concise names
  • break functionality into smaller composable pieces (-> Jinja filters) rather than a single macro that does it all

Common Use Cases

  • include a section of another file based on lines

    {{ includex("file.md", start=5, end=10) }} vs. --8<-- "file.md:5:10"

  • include a section of another file based on line content

    {{ includex("file.py", start_match="def foo", end_match="return ") }}

  • include another file as a code block with a caption

    {{ includex("file.yaml", code="yaml", caption=True) }}

  • include another file as a code block within a collapsed admonition

    ??? quote "file.yaml"
    
        {{ includex("file.yaml", lang="yaml", indent=4) }}

While all of these don't look bad in their minimal form presented here, they become tedious to write fast. Also, longer and more nested files means the total length of the expression often exceeds what is deemed acceptable (80, 88 or even 100 characters).

@jannismain
Copy link
Owner Author

jannismain commented Sep 8, 2023

Proposal: Positional Arguments

Include 2 or more positional arguments which are parsed by their type. int would indicate line numbers, str indicates match patterns.

  • {{ includex("file.md", 5, 10) }}: include lines 5-10 from file.md
  • {{ includex("file.md", "def foo", "return ") }}: include section starting with def foo and ending with return from file.md

Verdict

➕ less typing required
➖ slightly less readable at the call site

@jannismain
Copy link
Owner Author

jannismain commented Sep 8, 2023

Proposal: Extend File Argument

Extend first argument with additional information about start and end of the inclusion, separate values using ::

  • includex("file.md:5:10")
  • includex("file.md:def foo:return ")

Verdict

➕ concise

probably the most concise syntax possible (for a macro)

➖ clashes with VSCode syntax

In VSCode, file.md:5:10 means line 5 at position 10.

♻️ Using two distinct separators?

Using another character (e.g. "file.md:5-10") would mean more special cases to be handled (as both : and - are reserved and need to be escaped now). The parser would get more complicated.

It would match the caption currently generated (file.md, lines 5-10) and so is maybe the most intuitive option.

- clashes with negative indices ("file.md:-5" for including the last 5 lines).

➡️ - should not be used as a separator, sticking to a single separator allows for less escaping and easier parsing.

➖ Seperator needs to be escaped when needed in match string

Example: "file.py:foo()::return"

A simple arg.split(":") no longer works, as it is now ambiguous which : is part of the match string.

Wrapping those instances in ' would remove the ambiguity and allow for those instances to be detected using a slightly more sophisticated parser ("file.py:'foo():':return"). It also allows for numbers to be interpreted as match string instead of line numbers ("file.md:'5':'6'" to match a block that starts with a literal 5 and ends with the literal 6). However, what about when ' needs to be matched?

Another option would be to use | as in "file.md|5|10". | is less likely to occur in some documents (e.g. written in English, Python, ...) and so is a less likely target for a match string that would need to be escaped compared to :. However, it looks less appealing and is harder to type.

@jannismain
Copy link
Owner Author

jannismain commented Sep 8, 2023

Combine line and match parameters

For a more minimal interface, the start: int (meaning start line number) and start_match: str (meaning first line matching this string) can be combined into a single parameter. Parsing this parameter would need to determine, whether a line number of match string is given.

➕ more minimal interface (less parameters for user to remember)
➖ matching numbers would no longer work (number would always be interpreted as line numbers)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant