Re: [PATCH 0/9] Allow literal tabs in reStructuredText

Guenter Milde via Docutils-develop <[email protected]>
Newsgroups gmane.text.docutils.devel
Message-ID <[email protected]>
Dear Jax,

On 2023-10-29, Jarret "Jax" Renker via Docutils-develop wrote:

> I'm sending you a draft on how to handle literal tab characters inside
> reStructuredText documents.

Thank you for the suggestion and patch set!

I finally found the time to "immerse myself" into the TAB problem.
Sorry for the late answer.

...
> Currently it is impossible for the *output* of a literal block to
> contain tabs. This breaks some listings, e.g. Makefile:
...
> This behaviour is also contrary to my expectation that a literal block
> leaves its content untouched.

This is indeed one of the "warts"¹ in Docutils.

¹ Things that are ugly but kept for "practical reasons".

...
> Currently, the tab character is only supported for included CSV tables
> but not for inline ones.
...

This is a valid complaint, too, but it is less strong than the
"literal-block" one, as it should be not too much pain for authors to
change to a different delimiter for *embedded* CSV values. (The output
uses a different delimiter anyway.)


Now we have to find out, if solving these issues without introducing a
bunch of new problems is possible and worth the effort.


> The problem is that all tab characters get replaced *prior* to parsing,
> namely in string2lines().


> An attempt for a solution
>=========================

> In an attempt to fix this, I toyed around with not replacing tab
> characters before parsing but handling them during parsing.  The parts
> concerned with indention parsing are the methods trim_left() and
> get_indented() of StringList. Adjusting them lets things "just
> work(tm)".  This is a draft, so some details and corner cases must
> still be sorted out.

The draft demonstrates a possible way forward and solves the issue in
"well behaved" cases.

Unfortunately, there are set of small issues, some failures and a general
problem. Let's start with the last:


Generic Problem: shifting post-tab text.
----------------------------------------

TAB expands to a 1 … tab-width spaces, depending on position::

    for i in range(8):
        s = f"{i*'·'}\t{(8-i)*'·'}"
        print((s, s.expandtabs(8)))

Therefore, shortening from the left affects the expansion of the remainder::

    from docutils.statemachine import logical_rslice  # added in patch 4/9

    sample = 3 * '·\t·'
    print(f'{sample=}')
    print('i sample shortened by i and expanded')
    print('- ----------------------------------')
    for i in range(8):
       print(i, i*' ', repr(logical_rslice(sample, i, 8).expandtabs(8)))
    print()


This may break documents, e.g. if a table is aligned with TABs:

table::
    ==========  ==
    Mueller\t3
    Maier\t1
    Maierhuber\t5
    ==========  ==

(Mind, that in rST, you may nest a literal block in a table cell!)


Workaround: 
  Request that block-indentation must be a multiple of "tab-width"
  if there are literal TABs in an indented text block.

  `docutils.statemachine.logical_rslice()` may issue a Warning and
  expand the remainder before returnig if there are TABs in it.

...

> Obviously we should somehow use the docutils.conf option tab_width.

Indeed. Unfortunately, I am not familiar with the parser, too, and its
author David Goodger is less active on docutils-develop nowadays.


Test failure 
------------

The test suit (alltests.py) fails after applying the patches. 
The failing test is in
test/test_parsers/test_rst/test_directives/test_include.py 
(custom TAB expansion with included code),
so this may be an aftereffect of not observing the "tab-width" setting.

I found some more problematic cases, some of them relate to the
`generic problem` above but there seems to be at least one more problem
with nested parsing...

~~~
from docutils.core import publish_parts

sample = """
This is a simple test

        a block
                with definition list (space indented)

        a block
\t        with definition list (TAB + space indented)

\ta block
\t\twith definition list (TAB indented)

        A block
        \twith definition list (space + TAB indented)

.. note::
\tsomething
\t\tis up

a literal block::

\t  less\tindented first line
\t\tdo we want leading spaces here?

A table using TABs for alignment

==========      ==
Mueller\t\t3
Maier\t\t1
Maierhuber\t5
==========      ==

A similar table in a block-quote

    ==========  ==
    Mueller\t3
    Maier\t1
    Maierhuber\t5
    ==========  ==
"""

print(publish_parts(sample)['whole'])

~~~

Smaller Problems
----------------

:1/9: parsers.rst.Parser.parse() and statemachine.string2lines() are
      part of the API: changes must be backwards compatible or announced
      in the RELEASE-NOTES 2 releases in advance.
      → e.g., tab_width < 0 → don't replace
:2/9: dito. → Test for old and new behaviour.

:3/9: → We need more test cases for "mixed" indentation and different
      `tab-width`. (maybe later)
      
:4/9: term "logical": are there analogues, precedences?
      suggestion: logical → expanded | tab_expanded | ...?
        
      logical_rslice(): "rslice()" was proposed as a reverse variant of
      the "slice()" standard function.
      → shorten(s, by, tab_width) | lshorten(s, by, tab_width)

sincerely,

Günter



_______________________________________________
Docutils-develop mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/docutils-develop

Please use "Reply All" to reply to the list.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.