~mrshll1001/gmi2html

Very basic Python gemtext to HTML converter I wrote for fun
Added thanks and gratitude
Fix error in example

refs

main
browse  log 

clone

read-only
https://git.sr.ht/~mrshll1001/gmi2html
read/write
git@git.sr.ht:~mrshll1001/gmi2html

You can also use your local clone with git send-email.

#gmi2html

A simple Gemtext to HTML parser for Python which aims to be straightforward and importable for your Python-based Gemini projects.

This was built to serve my own specific use-case, since none of the results on PyPI.org appeared to match my needs to provide Gemtext -> HTML conversion as an importable library. huntingb/gemtext-html-converter also exists and is probably much better written, but I wanted to experiment for myself as well try to produce something that was a self-contained Python module.

The output for this is fairly non-fancy: you might want to prettify or clean the HTML if you want to write it to a file or include it in another document.

Feature list:

  • Parses gemtext according to Section 5 of the Gemini Specification and the Quick Introduction to "Gemtext" markup documents.
  • Links (=>) are parsed with optional link text. Any links without link text have the target repeated inside the anchor tags e.g. => gemini://example.org becomes <a href="gemini://example.org>gemini://example.org"</a>
  • Lists (*) are parsed as unordered lists, with opening and closing <ul> tags.
  • Blockquotes (>) are rendered using <blockquote> tags
  • Headers (#, ##, and ###) become the appropriate <h1>, <h2>, or <h3> header tag.
  • Preformatted text (```) renders using <pre> tags, and preserves newlines within the block.
  • Text lines render between <p> tags.

Non-features (that will not be implemented):

  • HTML to Gemtext conversion (i.e. round-tripping): that's not the job here, use a dedicated HTML to Gemtext converter.
  • Boilerplate: I experimented with including a standalone parameter, but it added more state and it's difficult to tell from Section 5.5.1 of the Gemini specification whether # Heading One should be analagous to <title>Heading One</title> as well as <h1>Heading One</h1>.
  • Prettifying or formatting: Owing to the fact HTML doesn't really care about newlines outside of preformatted text, the parser is pretty brutalist with regards to its output. No attempt is made to prettify. I didn't want this library to have a lot of dependencies, and to do one thing reasonably well. Please just run the output through a formatter/prettifier for your use-cases.

#Project Status

This is a pet project designed to act as a library to support my other gemini pet project. It won't be under proactive development once I've confirmed it's behaving as intended.

This said, I'd like it if it were useful to others. I will try my best to respond to Merge requests and Issues, but I am not a professional Python developer.

I will be using semantic versioning to version the project. I do not envision the project to go far beyond version 1.0 because Gemtext is stable. I will mostly be bugfixing and don't intend to add many features or functionality. Therefore there may be many 1.0.x versions.

Until I'm confident that it's behaving as expected, the project is at Version 0.1.0.

#Installation

The goal is to enable you to install this library via pip, and possibly to build some package files for package managers for GNU/Linux users to manage the library through their distro package manager. Watch this space.

#Usage

Simply import into your project, instantiate, and then call parse() on your gemtext input.

from gmi2html import Gmi2HTML

parser = Gmi2HTML()

# Parse a string
gemtext = "# Example Gemtext\nHello Gemini! Insert Space Metaphor here!"

result = parser.parse(gemtext) # "<h1>Example Gemtext</h1><p>Hello Gemini! Insert Space Metaphor here!</p>"

# Parse a whole document

with open('./tests/test-gemtext-file.gmi', 'r') as gmi_file:
	gemtext = gmi_file.read()
	parser.parse(gemtext)

# Combine with other projects to build more complex things
# https://pypi.org/project/ignition-gemini/

import ignition

response = ignition.request("gemini://gemini.circumlunar.space/")

html = parser.parse(response.data())

#Support

Please feel free to open issues! I'm not a particularly advanced Python programmer so I am also very open to Merge requests if you provide a summary of the changes and ensure your code is commented thoroughly.

#Roadmap

Ideally the following will be implemented in the future:

  • Enable installation via pip package manager
  • Makefile supporting generating a .deb file
    • And an Arch package file? At least compatibility with AUR would be a good step
  • Other people contribute refactoring / style changes to make more pythonic, more efficient, and/or more readable.

With support / learning:

  • Inclusion in Debian and/or Devuan repos.

#Contributing

I am very open to contributions.

My requirements are:

  • you are polite and respectful of others and do not have a history of using abusive/hateful language towards others. While it is overkill and boilerplate, CODE_OF_CONDUCT.md stands and any theoretical future contributors will be booted if you're toxic.
  • your code is well documented (this can mean different things to different people, but comments on complex functions and blocks to support reviewing and code transparency are a must)
  • you clearly communicate the motivations for your contributions and/or changes, and are open to explaining them if I or others do not understand (comments on code can help head this off!)

Your code should pass the unit tests. Please run them via:

python3 -m unittest -v tests/parser_tests.py

If you can write some better unit tests, that'd be very cool and I'd love to learn from you.

I generated some boilerplate in CONTRIBUTING.md which should cover most other contributory-style things.

#License

Licensed using the GPL 3, which means your software should be too if you're using this as a library.

#Thanks and gratitude

  • Solderpunk, for the Gemini protocol specification
  • The Gemini community for creating such awesome content
  • Joffrey Bienvenu, for the great starter guide on creating a Python library.
    • Related, the team behind scribe.rip for making it possible to read Joffrey's guide without being assaulted by Medium's interface.