Library / SDK
sylvainhalle/textidote avatar
sylvainhalle/textidote

TeXtidote maps LanguageTool findings back onto LaTeX source lines

Spelling, grammar and style checking on LaTeX documents

1,060 stars75 forksJavaGPL-3.0

At a glance

What is it?
TeXtidote is a Java linter for LaTeX and Markdown that strips markup, hands the plain text to LanguageTool, then translates the messages back to exact line and column positions in your original file. It also ships its own structural rules for figures, citations and section titles, and it is GPL-3.0 licensed with no recent release tag.
Who is it for?
TeXtidote suits an academic or technical writer who wants spelling and grammar feedback on a LaTeX draft without pasting text into a web form, and who will accept running a JAR or a Docker image on their own machine so the manuscript stays local.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 59 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • sylvainhalle/textidote1,060 ★ · +2
Star history
Repository2026-10-212026-11-07
sylvainhalle/textidote1.1k1.1k

2 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Why a grammar checker cannot read a LaTeX file directly

The problem TeXtidote was written to solve is stated as a question in the README: have you ever thought of using a grammar checker on LaTeX files? The answer given is that the process is far from simple, for a specific structural reason.

LaTeX documents contain special commands and keywords, the so-called markup, which are not part of the real text. A grammar checker cannot tell markup from text on its own. Stripping the markup first is the other option, but then a message pointing at line 40 of the clean text is almost impossible to retrace in the original file, because the clean text has a different line numbering than the source.

TeXtidote's answer is to keep track of the relative position of words between the original and the clean text. That mapping is what lets it translate LanguageTool messages back to their proper location directly in the source file. In other words, the hard part of the project is not the checking, it is the position bookkeeping that makes the check actionable.

The audience is people who write LaTeX for a living and want the same class of feedback they would get in a word processor, on a format that word processors handle badly. The project also supports spelling and grammar checking of files in the Markdown format, which widens the target a little.

LanguageTool does the checking, TeXtidote owns the rules and the mapping

The architecture has two halves. TeXtidote can read a LaTeX file and perform sanity checks on it itself, for example making sure that every figure is referenced in the text or enforcing correct capitalization of titles. Separately, it removes the markup and sends the resulting text to the LanguageTool library, which performs verification of both spelling and grammar in a dozen languages.

What is unique to TeXtidote, per the README, is that it maintains the position mapping between the original and the clean text so the LanguageTool messages come back as file locations rather than as offsets into a stripped copy.

The built-in checks are organised as rules, and each rule has an identifier. In a report you see an identifier in brackets, such as `sh:001` for a section title that should start with a capital letter, `sh:002` for a section title that should not end with punctuation, and `sh:c:001` for a missing space before a citation or reference. The README states that the full list of all the rules checked is given at the end of the file, which means the rule set is documented rather than implicit.

That rule model matters for adoption. A linter that reports problems you cannot turn off is a nuisance in a document that uses a house style, and a rule-per-identifier system is what makes selective enabling possible.

Three report formats, and the one meant for scripts

TeXtidote produces three kinds of report, and the choice matters more than it might seem because the formats are aimed at different consumers.

The HTML report shows your original LaTeX source file with problem regions highlighted in various colors, and hovering over a region reveals a message describing the problem. It is the format for a human reading a result.

The plain report is the console format. Each warning gives its position in the original source file, where `LxxCyy` means line xx, column yy, followed by a short comment and an excerpt of the line with the offending range marked underneath by `^^^^` symbols. A warning also carries the identifier of the rule that produced it.

The single-line report is the one aimed at other tools. Each warning is one line of text in a regular shape:

text
example.tex(L25C1-L25C25): A section title should start with a capital letter. "\section{a first section}"
example.tex(L38C1-L38C29): A section title should not end with a punctuation symbol. "\subsection{ My subsection. }"

The README says each line corresponds to a warning and is parseable by regular expressions easily, for further processing in another tool. That is the format to use if you want to fail a continuous integration job on a new spelling error, since it is the only one of the three with a stable, greppable shape.

If you write no filename, or write `--` as the filename, TeXtidote attempts to read one from standard input, which makes it usable in a pipe.

Installing a JAR, a Debian package or the Docker image

The README offers a manual download and a package route.

For Debian systems, including Ubuntu and derivatives, the instructions are to download the latest `.deb` file from the Releases page and install it, where the file is assumed to be called `textidote_X.Y.Z_all.deb`:

bash
sudo apt-get install ./textidote_X.Y.Z_all.deb

The README calls the `./` mandatory, because without it the command does not work. That is the sort of detail that turns into a support question otherwise.

For a manual install, download the latest release and put the JAR wherever you like. The only stated requirement is Java version 8 or later, and this route works on all operating systems.

Running it needs the JAR and a file to check. The repository contains a sample LaTeX file called `example.tex`, and the documentation suggests downloading it and saving it into the folder where TeXtidote resides, then producing a report:

bash
java -jar textidote.jar --output html example.tex > report.html

On Linux, if you installed with `apt-get`, you can call the tool directly:

bash
textidote --output html example.tex > report.html

The `--output html` option selects the format and the `>` redirection saves the output to a file. The run prints a banner, the number of warnings found and the total analysis time.

A container route exists too. The Dockerfile in the repository root builds with Ant on an openjdk:8 base, runs the `wipe`, `download-deps` and default Ant targets, and the resulting image copies `textidote-0.9.jar` to `/textidote.jar` with an entrypoint of `java -jar /textidote.jar`. The image therefore ships one specific version, 0.9.

The grammar check is only half the output

It is easy to read TeXtidote as a LanguageTool wrapper and miss what it does on its own.

The structural checks are the part that catches LaTeX-specific mistakes that a language checker has no way of seeing. The sample warnings in the documentation show a section title that should start with a capital letter, a section title that should not end with a punctuation symbol, and a missing space before a citation or reference. The README also names the category of check that makes sure every figure is referenced in the text, and enforcing the correct capitalization of titles.

The third example shows why these are worth having. A missing space before `\cite{my:paper}` is invisible to a reader and to a spelling checker, and it is exactly the sort of thing that survives copy and paste from a PDF or from a collaboration tool. The rule identifiers shown in the brackets make it clear which family a warning belongs to.

So the practical division of labour is this. LanguageTool catches language problems in the prose, and TeXtidote's own rules catch LaTeX conformance problems. A document that needs both gets both, and the report does not distinguish them by format, only by rule identifier.

What the documentation does not settle

There are a few gaps that a reader will notice, and it is better to name them than to guess.

The README as provided stops partway through the single-line report section, so the details of that format, including the exact trailing fields, are cut off. The rule list that the README says appears at the end of the file is also not visible in the text available here. Both are in the upstream file, but a reader working only from what is published here will not have them.

Configuration is the other gap. The tool clearly supports language selection and per-rule configuration, and the report formats are switchable, but the documentation excerpt does not show the option names for language selection, for choosing the LanguageTool version, or for enabling and disabling individual rules. The option names that do appear are limited to `--output`, with `html`, `plain` and `singleline` as values.

The project also carries files that hint at capability the README does not describe. At the repository root there is a `dictionary.txt`, a `mymap.txt`, a `Completions/` directory and a `config.xml`, alongside `build.xml` for the Ant build, a `CITATION.cff`, and `docs/`. A word list and a mapping file at the root usually mean project-specific vocabulary and abbreviation handling, and a `Completions/` directory usually means shell completion definitions, but the README does not describe how to use them, so treat that as an inference from the layout rather than a documented feature.

One more practical constraint: LanguageTool works in a dozen languages, and the accuracy of any grammar check depends on the language configuration matching the document. The README does not specify which languages are supported or how to select one.

Where TeXtidote is the wrong tool

Three cases stand out.

First, the checking depends on an external library for anything beyond the built-in structural rules, and the docs do not describe whether LanguageTool runs locally, is bundled, or is reached over the network. A writer with a confidential manuscript, a grant proposal or an unpublished paper has a reason to care about that before running the tool on it.

Second, this is a batch linter, not an editor plugin. You run it over a file and read a report. It will not underline a suspect phrase while you type, and it will not reformat your document. If what you want is inline feedback in the editor as you write, this is the wrong shape of tool, whatever its accuracy.

Third, the LaTeX it understands is the LaTeX whose markup it can recognise. A document that leans on custom macros, heavy verbatim blocks or unusual packages may have text that the stripper cannot separate cleanly from markup. The mapping feature protects the accuracy of positions, but it cannot protect against text that was never properly identified as text in the first place.

For a plain English manuscript, a word processor with grammar checking already covers most of the ground. TeXtidote earns its place specifically because of LaTeX, and because the results come back as source locations rather than as a cleaned copy of your prose.

Editorial conclusion

TeXtidote suits an academic or technical writer who wants spelling and grammar feedback on a LaTeX draft without pasting text into a web form, and who will accept running a JAR or a Docker image on their own machine so the manuscript stays local. It does not suit a team that needs a maintained release cadence, since the newest tagged build in the repository is v0.9 from 2026-03-25 with a v0.9-beta1 draft still listed separately, and it does not suit a workflow that requires the checker to be a plugin inside the editor rather than a separate process. Verify three things before wiring it into a build: that the rule set you rely on is enabled for your document, since the built-in checks are switchable per rule, that your LaTeX macros do not hide text from the markup stripper, and that the LanguageTool language and version settings produce the accuracy you need for your document before you make the single-line output a CI gate.

Frequently asked questions

How do I install TeXtidote on Debian or Ubuntu?

Download the latest `.deb` file from the Releases page and install it with `sudo apt-get install ./textidote_X.Y.Z_all.deb`. The README notes that the `./` before the filename is mandatory, otherwise the command does not work.

What Java version does TeXtidote require?

Java version 8 or later is required for the manual download route, which works on all operating systems. The Dockerfile at the repository root also builds on an openjdk:8 base image.

How do I get a TeXtidote report I can parse from a script?

Use the single-line format with `java -jar textidote.jar --output singleline example.tex`. The README says each line corresponds to one warning and is parseable by regular expressions easily, for further processing in another tool.

Does TeXtidote check spelling and grammar, or only LaTeX structure?

Both. TeXtidote removes the markup and sends the text to the LanguageTool library, which verifies spelling and grammar in a dozen languages, and it also runs its own structural rules such as making sure every figure is referenced in the text and that section titles are capitalized correctly.

Can TeXtidote read from standard input?

Yes. If you write no filename, or write `--` as the filename, TeXtidote attempts to read one from the standard input, which makes it usable in a pipeline.

Official sources

  1. License: GPL-3.0
  2. Project website
  3. README
  4. Releases
  5. sylvainhalle/textidote on GitHub

Was this useful?