Plint
- 14 Devlogs
- 36 Total hours
Plint is a linter for text files. Plint finds predefined errors and warnings in the text files. Download the rulesets from the Internet and use it right away.
Plint is a linter for text files. Plint finds predefined errors and warnings in the text files. Download the rulesets from the Internet and use it right away.
I’ve added an example ruleset for reviewers and raters (I don’t know what they are named) to test my linting language quickly without writing one themselves.
The program on the screenshot is a rule that flags headings that are not continuous from the previous headings (like jumping from H1 to H3).
Honestly, this language is way more expressive than I first thought. I thought it would be impossible to detect skipping levels, but it could.
I created README.md and added some information to it.
I also added a sample linter program:
for sentence in sentences(doc) (
length = char_count(doc, sentence)
words = word_count(doc, sentence)
has_hedging = or(
contains(doc, sentence, "I think"),
contains(doc, sentence, "I believe"),
contains(doc, sentence, "perhaps"),
contains(doc, sentence, "probably")
)
if and(
gt(length, 100),
gt(words, 15),
has_hedging
) (
sentence
)
)
I’ve completed implementing my custom language for linting documents, and I added a few more functions to it.
Sample program:
for match in sentences(doc) (
if gt(char_count(doc, match), 100) (
match
)
)
In this language, for and if are statements. This means that they can return values.
for collects non-null values and returns the list of values. if returns the value if it exists, and null if the value is not returned in it or the condition is false.
My plint CLI shows the errors on the position of the returned matches.
I implemented a few more commands:
ruleset check: Check if the ruleset is valid
ruleset create: Create a new ruleset
ruleset edit: Open the ruleset YAML file in the default editor
ruleset list: List all rulesets
group create: Create a new group
group edit: Open the group YAML file in the default editor
group add-set: Add the ruleset to the group
group remove-set: Remove the ruleset from the group
group list: List all groups
You may wonder why I removed it after more than 5 hours of coding. Here’s why.
I wanted to achieve something like this:
Ruleset
> Name: rule-foo-bar
Authors: Alice
Description: This is a placeholder description.
Version: 1
Edit Rules
← Back
I tried inquire and Ratatui to implement this. However, both of them was not suitable for this after all.
inquire
inquire is a very simple crate to ask users some question on CLI.
The main problem was that I could not add multiple fields and let user edit multiple fields in the same screen (like above), which means that the implementation had to be like this:
Select what to edit
> Name
Authors
Description
Version
Back
and I wanted to avoid this.
Ratatui
Ratatui is a crate to build a “TUI” application in Rust.
It is very powerful, but I found it a bit over-engineered for my use case. Also, it is mainly designed for full-screen terminal application and was not suitable for inline CLI application like mine.
I also tried to make a CLI library myself, but I decided not to do so. (You can find my library repository here.)
I used crossterm and I had to calculate the position of the cursor, characters and I also had to count unicode characters and calculate the widths for them. I thought that this was not worth it, especially because I didn’t have so much time before the summer break ends.
For now, I decided to make edit command just open the default editor and implement other things, and make the CLI after adding all other essential features.
I added the basic linting logic and I tested if it works.
As you can see in the video, linting works nicely and it successfully returns the matches.
Here’s the example rule set I used in the video:
name: basic-ruleset
description: This is a basic ruleset.
version: 1
rules:
- id: no-hello
message: '"hello" is not allowed.'
severity: error
checker: std.regex
args:
pattern: hello
- id: invalid-hello
message: '"helloooo" is not allowed.'
severity: error
checker: std.regex
args:
pattern: helloooo