Preserve tabs in Sphinx Makefile code-block's - python-sphinx

I use Sphinx with reStructuredText input and HTML output to document different pieces of the infrastructure. The idea is that a user who reads the documentation can copy examples and past them into her file. How can that be done for Makefile examples? Makefiles need tab characters at certain places, but Sphinx converts tabs into spaces.
Example: The command line must start with a tab in the final HTML. Here it is written with three spaces for indent and a tab:
.. code-block:: Makefile
target: dependency
command -i $< -o $#
code-block does not have an option to control tab expansion.
A web search with sphinx code-block makefile tab has answers for tab expansion in included code (I prefer to have it inline) or how the Sphinx Makefile can be edited, but nothing that soles my problem.

Tab expansion happens very early stage of parsing RST, so you have to customize parser itself to disable it. I hope this works.
from typing import Union
from docutils.nodes import document
from docutils.statemachine import StringList
from sphinx.parsers import RSTParser
class NoTabExpansionRSTParser(RSTParser):
def parse(self, inputstring: Union[str, StringList], document: document) -> None:
if isinstance(inputstring, str):
lines = inputstring.splitlines()
inputstring = StringList(lines, document.current_source)
super().parse(inputstring, document)
def setup(app):
app.add_source_parser(NoTabExpansionRSTParser, override=True)
FYI, here's where tab expansion happens, which is bypassed by the above code.
In sphinx.parsers.RSTParser#parse
lines = docutils.statemachine.string2lines(
inputstring, tab_width=document.settings.tab_width,
convert_whitespace=True)
↓
In docutils.statemachine.string2lines
return [s.expandtabs(tab_width).rstrip() for s in astring.splitlines()]

Related

How to get inline code ending with spaces with docutils/sphinx?

The following rST directive doesn't support trailing spaces:
:code:`foo `
Example:
>>> from docutils import core
>>> whole = core.publish_parts(""":code:`x `""")['whole']
<string>:1: (WARNING/2) Inline interpreted text or phrase reference start-string without end-string.
Is there a way to get rid of this warning?
No. According to the docutils documentation of Inline markup recognition rules:
Inline markup end-strings must be immediately preceded by non-whitespace.

Pandoc - is tex output with dollar sign math possible?

Is it possible to have .tex files output from pandoc have math mode with dollar signs ($)? The manual says:
LaTeX: It will appear verbatim surrounded by \(...\) (for inline math) or \[...\] (for display math).
I also found this Github issue from 2016 where the author says it could be selectable. Is there now a pandoc argument or another way of having the .tex output use dollar signs?
You can do this using a pandoc filter. E.g.:
-- Do nothing unless we are targeting TeX.
if not FORMAT:match('tex$') then return {} end
function Math (m)
local delimiter = m.mathtype == 'InlineMath' and '$' or '$$'
return pandoc.RawInline('tex', delimiter .. m.text .. delimiter)
end
Save to file dollar-math.lua, and pass it to pandoc via --lua-filter=dollar-math.lua.

jamplus: link command line too long for osx

I'm using jamplus to build a vendor's cross-platform project. On osx, the C tool's command line (fed via clang to ld) is too long.
Response files are the classic answer to command lines that are too long: jamplus states in the manual that one can generate them on the fly.
The example in the manual looks like this:
actions response C++
{
$(C++) ##(-filelist #($(2)))
}
Almost there! If I specifically blow out the C.Link command, like this:
actions response C.Link
{
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,#($(2:TC)) $(NEEDLIBS:TC) $(LINKLIBS:TC))
}
in my jamfile, I get the command line I need that passes through to the linker, but the response file isn't newline terminated, so link fails (osx ld requires newline-separated entries).
Is there a way to expand a jamplus list joined with newlines? I've tried using the join expansion $(LIST:TCJ=\n) without luck. $(LIST:TCJ=#(\n)) doesn't work either. If I can do this, the generated file would hopefully be correct.
If not, what jamplus code can I use to override the link command for clang, and generate the contents on the fly from a list? I'm looking for the least invasive way of handling this - ideally, modifying/overriding the tool directly, instead of adding new indirect targets wherever a link is required - since it's our vendor's codebase, as little edit as possible is desired.
The syntax you are looking for is:
newLine = "
" ;
actions response C.Link
{
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,#($(2:TCJ=$(newLine))) $(NEEDLIBS:TC) $(LINKLIBS:TC))
}
To be clear (I'm not sure how StackOverflow will format the above), the newLine variable should be defined by typing:
newLine = "" ;
And then placing the carat between the two quotes and hitting enter. You can use this same technique for certain other characters, i.e.
tab = " " ;
Again, start with newLine = "" and then place carat between the quotes and hit tab. In the above it is actually 4 spaces which is wrong, but hopefully you get the idea. Another useful one to have is:
dollar = "$" ;
The last one is useful as $ is used to specify variables typically, so having a dollar variable is useful when you actually want to specify a dollar literal. For what it is worth, the Jambase I am using (the one that ships with the JamPlus I am using), has this:
SPACE = " " ;
TAB = " " ;
NEWLINE = "
" ;
Around line 28...
I gave up on trying to use escaped newlines and other language-specific characters within string joins. Maybe there's an awesome way to do that, that was too thorny to discover.
Use a multi-step shell command with multiple temp files.
For jamplus (and maybe other jam variants), the section of the actions response {} between the curly braces becomes an inline shell script. And the response file syntax #(<value>) returns a filename that can be assigned within the shell script, with the contents set to <value>.
Thus, code like:
actions response C.Link
{
_RESP1=#($(2:TCJ=#)#$(NEEDLIBS:TCJ=#)#$(LINKLIBS:TCJ=#))
_RESP2=#()
perl -pe "s/[#]/\n/g" < $_RESP1 > $_RESP2
"$(C.LINK)" $(LINKFLAGS) -o $(<[1]:C) -Wl,-filelist,$_RESP2
}
creates a pair of temp files, assigned to shell variable names _RESP1 and _RESP2. File at path _RESP1 is assigned the contents of the expanded sequence joined with a # character. Search and replace is done with a perl one liner into _RESP2. And link proceeds as planned, and jamplus cleans up the intermediate files.
I wasn't able to do this with characters like :;\n, but # worked as long as it had no adjacent whitespace. Not completely satisfied, but moving on.

How to embed shell snippets in doxygen documentation

When installing my package, the user should at some point type
./wand-new "`cat wandcfg_install.spell`"
Or whatever the configuration file is called. If I put this line inside \code ... \endcode, doxygen thinks it is C++ or... Anyway, the word "new" is treated as keyword. How do I avoid this is in a semantically correct way?
I think \verbatim is disqualified because it actually is code, right?
(I guess the answer is to poke that Dimitri should add support for more languages inside a code block like LaTeX listings package, or at least add an disableparse option to code in the meantime)
Doxygen, as of July 2017, does not officially support documenting Shell/Bash scripting language, not even as an extension. There is an unofficial filter called bash-doxygen. Simple to setup: only one file download and three flags adjustments:
Edit the Doxyfile to map shell files to C parser: EXTENSION_MAPPING = sh=C
Set your shell script file names pattern as Doxygen inputs, like
e.g.: FILE_PATTERNS = *.sh
Mention doxygen-bash.sed in either the INTPUT_FILTER or the
FILTER_PATTERN directive of your Doxyfile. If doxygen-bash.sed is in
your $PATH, then you can just invoke it as is, else use sed -n -f /path/to/doxygen-bash.sed --.
Please note that since it uses C language parsing, some limitations apply, as stated in the main README page of bash-doxygen, one of them, at least in my tests, that the \code {.sh} recognises shell syntax, but all lines in the code block begin with an asterisk (*), apparently as a side-effect of requiring that all Doxygen doc sections have lines starting with double-hashes (##).

Can I add scope information to tags generated with `--regex-<LANG>` in exuberant ctags?

Technically, I'm using Tagbar in vim to view a file's tags, but this question should apply generally to exuberant ctags, v5.8.
Suppose I've got the following python file, call it foo.py:
class foo:
def bar(baz):
print(baz)
Let's run ctags on it: ctags foo.py. The resulting tags file looks like this:
!_ some ctags version / formatting stuff not worth pasting
bar foo.py /^ def bar(baz):$/;" m class:foo
foo foo.py /^class foo:$/;" c
The bit I'm interested in is the last field of the second line, class:foo. That's the scope of the bar() function. If I use tagbar in vim, it nests the function in the class accordingly.
Now suppose I'm adding support for a new language in my ~/.ctags. In fact, I'm adding support for this puppet file:
class foo {
include bar
}
Suppose I use the following ~/.ctags arguments. The 'import' regex is ugly (errr... ugly for regex) but it gets the job done enough for this example:
--langdef=puppet
--langmap=puppet:.pp
--regex-puppet=/^class[ \t]*([:a-zA-Z0-9_\-]+)[ \t]*/\1/c,class,classes/
--regex-puppet=/^\ \ \ \ include[ \t]*([:a-zA-Z0-9_\-]+)/\1/i,include,includes/
That generates the following tag in my tags file:
bar foo.pp /^ include bar$/;" i
foo foo.pp /^class foo {$/;" c
Notice neither line contains scoping information. My question is this: Is there anyway for me to construct the --regex-puppet argument, or --regex-<LANG> lines generally, to collect information about a tag's scope? To perhaps declare that tags meeting criterion A are always going to be scope-parents of tags meeting criterion B?
man ctags suggests no clear way to add arbitrary scope information, but I might be overlooking another solution (snipped slightly for emphasis):
--regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
Unless modified by flags, regexp is interpreted as a Posix extended regular expression. The replacement should expand for all matching lines to a non-empty string of
characters, or a warning message will be reported. An optional kind specifier for tags matching regexp may follow replacement, which will determine what kind of tag is
reported in the "kind" extension field (see TAG FILE FORMAT, below). The full form of kind-spec is in the form of a single letter, a comma, a name (without spaces), a
comma, a description, followed by a separator, which specify the short and long forms of the kind value and its textual description (displayed using --list-kinds). Either
the kind name and/or the description may be omitted. If kind-spec is omitted, it defaults to "r,regex". Finally, flags are one or more single-letter characters having the
following effect upon the interpretation of regexp:
b The pattern is interpreted as a Posix basic regular expression.
e The pattern is interpreted as a Posix extended regular expression (default).
i The regular expression is to be applied in a case-insensitive manner.
No, unfortunately that is not possible with the regex pattern support in ctags. The only way to get ctags to generate correct scopes is to write a parser as an additional module in C. I would like to add support for a better handling of new languages to ctags if I find the time, but so far that hasn't worked out and I'm also still unsure about the best approach.
If you're mostly interested in Tagbar support there is another approach, though: Tagbar supports arbitrary tag-generating programs as long as their output is compatible to the ctags one, so you could write a simple parser in, say, Python and configure Tagbar to use that. Have a look at :h tagbar-extend (especially the last subsection "Writing your own tag-generating program") if that would be an option for you.
I'm working on such feature at universal ctags project:
https://github.com/universal-ctags/ctags/pull/562
.
(Don't expect too much; regex parser is not enough for complicated syntax.
The new feature is for a language with simple syntax.)
Example 1::
$ cat /tmp/input.foo
class foo:
def bar(baz):
print(baz)
class goo:
def gar(gaz):
print(gaz)
$ cat /tmp/foo.ctags
--langdef=foo
--map-foo=+.foo
--regex-foo=/^class[[:blank:]]+([[:alpha:]]+):/\1/c,class/{scope=set}
--regex-foo=/^[[:blank:]]+def[[:blank:]]+([[:alpha:]]+).*:/\1/d,definition/{scope=ref}
$ ~/var/ctags/ctags --options=/tmp/foo.ctags -o - /tmp/input.foo
bar /tmp/input.foo /^ def bar(baz):$/;" d class:foo
foo /tmp/input.foo /^class foo:$/;" c
gar /tmp/input.foo /^ def gar(gaz):$/;" d class:goo
goo /tmp/input.foo /^class goo:$/;" c
Example 2::
$ cat /tmp/input.pp
class foo {
include bar
}
$ cat /tmp/pp.ctags
--langdef=pp
--map-pp=+.pp
--regex-pp=/^class[[:blank:]]*([[:alnum:]]+)[[[:blank:]]]*\{/\1/c,class,classes/{scope=push}
--regex-pp=/^[[:blank:]]*include[[:blank:]]*([[:alnum:]]+).*/\1/i,include,includes/{scope=ref}
--regex-pp=/^[[:blank:]]*\}.*//{scope=pop}{exclusive}
$ ~/var/ctags/ctags --options=/tmp/pp.ctags -o - /tmp/input.pp
bar /tmp/input.pp /^ include bar$/;" i class:foo
foo /tmp/input.pp /^class foo {$/;" c

Resources