gemtext

package module
v0.0.0-...-733fe4d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2021 License: Unlicense Imports: 4 Imported by: 0

README

go-gemtext

an implementation of a gemtext parser and formatter with support for extensions.

Documentation is not fully finished and the code hasn't been fully tested, but it should work

Parser

Included is the ability to parse all standard gemtext and the ability to be expanded with logic for additional linetypes for use as a markup language in web applications

Examples
A custom linetype parser
type Custom struct{}

func (Custom) Config() gemtext.LineConfig {
	return gemtext.LineConfig{
		CustomKey:           "custom",
		Prefix:              "::",
	}
}

func (EndOfLine) Parse(m gemtext.ParseMeta) (gemtext.Line, error) {
	return gemtext.Line{
		Text: m.Text,
	}, nil
}

HTMLRender

In /htmlrender is a formatter to turn the parsed gemtext into html, also with support for extensions

Examples
Custom Linetype formatter
type CustomHTML struct {}

func (h CustomHTML) Write(w io.Writer, l gemtext.Line, r LineReader) error {
	_, err := fmt.Fprintf("<p>%v</p>", l.Text)
	return err
}

GemRender

In /gemrender is a formatter to turn parsed gemtext with custom line types back into standard gemtext, such as if you are using gemtext as a markup language in a blog distributed to both html and gemtext, and you say define a custom linetype to insert images, naturally you'd render that differently for the gemtext and html versions

In html you'd just insert it directly via an image tag

...
<i src='image.png'>

And in gemtext you'd render it as a link to the image file

...
=> gemini://domain/image.png (image.png)

Or perhaps a link to a meta page about the image

...
=> gemini://domain/media/image

Containing links to the image in multiple formats

# Media / Image
an image of an old computer
=> gemini://domain/files/image.png
=> gemini://domain/files/image.jpg
Examples
Custom Linetype formatter
type CustomGem struct {}

func (h CustomGem) Write(w io.Writer, l gemtext.Line, r LineReader) error {
	_, err := fmt.Fprintf("```\n%v\n```", l.Text)
	return err
}

Documentation

Index

Constants

View Source
const (
	Heading1 heading = 1
	Heading2 heading = 2
	Heading3 heading = 3
)

Headings

View Source
const (
	LinkRef = MetaLink
)
View Source
const (
	PreformattedTextAlttext = MetaAlttext
)

Variables

View Source
var DefaultParser = NewParser(AllTypes(), nil)

DefaultParser is a parser with all the standard gemini types

View Source
var MinimalParser = NewParser(BasicTypes(), nil)

MinimalParser is a parser with only the basic types

Functions

func NewError

func NewError(line int, err error, usermsg string) error

NewError returns a new error

func UnfoldLineWrappedError

func UnfoldLineWrappedError(e error) (ok bool, line int, err error)

Types

type Error

type Error struct {
	Line    int
	UserMsg string
	Err     error
}

Error is an error with added metadata for a User focused error message and which the line the error happened at

func UnfoldError

func UnfoldError(e error) (ok bool, err Error)

UnfoldError returns the fields of an error

func (Error) Cause

func (e Error) Cause() error

Cause gives the error located in e

func (Error) Error

func (e Error) Error() string

func (Error) LineNumber

func (e Error) LineNumber() int

func (*Error) ShiftLineNumber

func (e *Error) ShiftLineNumber(by int) error

func (Error) Unwrap

func (e Error) Unwrap() error

Unwrap gives the error located in e

func (Error) UserErrorMessage

func (e Error) UserErrorMessage() string

type ErrorLine

type ErrorLine interface {
	LineNumber() int
}

ErrorLine is an error interface to report on which line an error occoured for use with custom multiline elements that can report an error, in either the parser or the formatter (only useful in multiline elements.)

recommended practice is to report the line as releative to the start of the element source text, and also implement ErrorLineModify so the parser or formatter can add the global line number to it

type ErrorLineModify

type ErrorLineModify interface {
	ShiftLineNumber(by int) error
}

ErrorLineModify is used to modify the line number reported by ErrorLine as to modify a relative line number to be the global line number if this is not supported, giving the absolute line number is recommended

type ErrorUserMessage

type ErrorUserMessage interface {
	UserErrorMessage() string
}

ErrorUserMessage is used to be able to attatch a user visible error message to an error. anything reported by this method may be shown to an end user. the output of this should not include the line number, that should be left to ErrorLine and whichever device happens to display the error to a user

type Formatter

type Formatter interface {
	Format(LineReader) []byte
}

type Line

type Line struct {
	Type LineType            // the type of formatting for this block
	Line int                 // the line this block is found on
	Meta map[MetaType]string // meta values

	Text   string // the basic text that should be shown to a user
	Source string // the source text it was generated from

	// only used if LineType == custom
	// functions as the identifier for custom formatting types
	CustomID string
}

type LineConfig

type LineConfig struct {
	CustomKey string // the identifier used by a custom type to identify itself to a formatter (must be unique)

	// the prefix that identifies a formatting structure (eg: => for links)
	// this is required unless you wish to override how text lines are parsed
	Prefix string
	// a suffix is required for multiline mode unless you wish for an element to extend to the end of text
	// not neecessary outside of multiline mode, as single line mode will always end at a new line
	// but it'll trim the suffix of in single line mode too
	Suffix string
	// TrimWhitespace causes it to trim and leading and trailing whitespace before calling the parse method
	// unless you need the whitespace or wish to trim it out yourself its recommended to just leave this on
	TrimWhitespace bool
	// multiline mode allows it to parse formatting that cover multiple lines
	// (such as preformatted text that starts and ends with “`)
	Multiline bool
	// only applicable in multiline mode
	// allows determining where it'll consider a valid suffix for multiline elements
	// default is BeforeNewline
	MultilineSuffixMode MultilineSuffixMode
}

LineConfig contains some settings for how the parser will treat LineParsers

type LineParser

type LineParser interface {
	Config() LineConfig
	Parse(ParseMeta) (Line, error)
}

LineParser is the interface used to define custom line types

func AllTypes

func AllTypes() []LineParser

AllTypes returns a slice containing all the standard gemtext linetypes it is safe to append to the returned slice to add custom types

func BasicTypes

func BasicTypes() []LineParser

BasicTypes returns a slice containing only the core line types of gemtext it is safe to append to the returned slice to add custom types

type LineReader

type LineReader struct {
	Lines []Line
	Index int
}

LineReader is a wrapper around a slice of lines for easy reading of the abstract syntax array it is safe to copy as it is assumed Lines will not change after creation

func (*LineReader) Continue

func (r *LineReader) Continue() bool

Continue returns true if there are more lines to read

func (*LineReader) Current

func (r *LineReader) Current() Line

Current returns the current line

func (*LineReader) Peek

func (r *LineReader) Peek(i int) Line

Peek returns the line + or - i it returns a line with type Invalid if the requested line is out of bounds

func (*LineReader) PeekAhead

func (r *LineReader) PeekAhead() Line

PeekAhead is an alias to Peek(1)

func (*LineReader) PeekBack

func (r *LineReader) PeekBack() Line

PeekBack is an alias to Peek(-1)

func (*LineReader) Reset

func (r *LineReader) Reset()

Reset the pointer to 0

func (*LineReader) Step

func (r *LineReader) Step() (l Line)

Step returns the current line and then increments the pointer by 1

type LineType

type LineType uint
const (
	LineTypeInvalid          LineType = iota
	LineTypeText                      // text
	LineTypeLink                      // link
	LineTypePreformattedText          // preformatted text
	LineType1stHeading                // 1st heading
	LineType2ndHeading                // 2nd heading
	LineType3rdHeading                // 3rd heading
	LineTypeUnorderedList             // unordered list
	LineTypeQuote                     // quoteblock
	LineTypeCustom                    // custom
)

LineTypes for the AST

func (LineType) String

func (i LineType) String() string
type Link struct{}

func (Link) Config

func (Link) Config() LineConfig

func (Link) Parse

func (Link) Parse(m ParseMeta) (Line, error)

type MetaType

type MetaType uint

MetaType is the key of a meta value there are the primary meta values, as consts prefixed with Meta and each builtin line type also has its own aliases of the keys they use

values 100 and below are reserved for internal use values above 100 can be used by custom linetypes

const (
	MetaLink    MetaType = iota // link
	MetaAlttext                 // alttext
)

MetaTypes

func (MetaType) String

func (i MetaType) String() string

type MultilineSuffixMode

type MultilineSuffixMode uint8
const (

	// require a suffix to exclusively on its own with a line
	// (assuming a suffix of :> it would require the text to be "...\n:>" followed by either /n or eof in order to count)
	MultilineSuffixExclusive MultilineSuffixMode = 1 // exclusive line

	// require the suffix to appear before a newline or eof in order to count
	// (assuming a suffix of :> "text:>\n" would be valid, but "text:>text" would not)
	MultilineSuffixBeforeNewline MultilineSuffixMode = 2 // before newline

	// allows the suffix to appear anywhere in text and not just when followed by a newline
	// anything that follows the suffix with this on will be treated as a newline even if its not
	// (assuming a suffix of :> and an input of `...eot:>moretext` moretext will be treated as if its on a new line)
	// if the suffix is followed by a newline it will still trim that however
	// (to avoid inserting a blank line that doesn't exist into the ast)
	MultilineSuffixAnywhere MultilineSuffixMode = 3 // anywhere

	// Default is BeforeNewline, see the docs on that for more
	MultilineSuffixDefault = MultilineSuffixBeforeNewline
)

modes for how to treat the suffix of multiline elements

func (MultilineSuffixMode) String

func (i MultilineSuffixMode) String() string

type ParseMeta

type ParseMeta struct {
	Text string

	// only used for multiline structures
	// tells you if there is a new line right after the prefix
	// for example with preformatted text
	//     “`
	//     example
	//     “`
	// would put this as false, there is only a newline after the prefix
	// while
	//     “`alt
	//     example
	//     “`
	// would put this as true, there is text on the prefix line
	TextOnPrefixLine bool
}

ParseMeta is the data given to line parsers

type Parser

type Parser struct {
	LineTypes []LineParser
}

Parser is a gemtext parser that outputs an AST

func NewParser

func NewParser(p []LineParser, _ *ParserConfig) *Parser

NewParser initialises a new parser

func (*Parser) Parse

func (p *Parser) Parse(s string) (LineReader, error)

Parse a gemtext document into an abstract syntax array wrapped with some additional methods for easy reading

under default circumstances error will always be nil error is only ever returned if a custom has an error

(bug) be aware as a side effect it currently converts CRLF documents to LF

type ParserConfig

type ParserConfig struct{}

ParserConfig ... currently unused reserved for future expansion ...

type PreformattedText

type PreformattedText struct{}

func (PreformattedText) Config

func (PreformattedText) Config() LineConfig

func (PreformattedText) Parse

func (PreformattedText) Parse(m ParseMeta) (Line, error)

type Quote

type Quote struct{}

func (Quote) Config

func (Quote) Config() LineConfig

func (Quote) Parse

func (Quote) Parse(m ParseMeta) (Line, error)

type UnorderedList

type UnorderedList struct{}

func (UnorderedList) Config

func (UnorderedList) Config() LineConfig

func (UnorderedList) Parse

func (UnorderedList) Parse(m ParseMeta) (Line, error)

type WrappedErrorWLine

type WrappedErrorWLine struct {
	Line int
	// contains filtered or unexported fields
}

WrappedErrorWLine is an error that contains an error and a line number if a custom formatting element or custom element formatter returns an error that does not have a line number, the formatter/parser will wrap the error in one of these types giving it a line number it implements the ErrorLine interface, and to unfold the contained error

func (WrappedErrorWLine) Cause

func (e WrappedErrorWLine) Cause() error

Cause gives the error located in e

func (WrappedErrorWLine) Error

func (e WrappedErrorWLine) Error() string

func (WrappedErrorWLine) LineNumber

func (e WrappedErrorWLine) LineNumber() int

func (*WrappedErrorWLine) ShiftLineNumber

func (e *WrappedErrorWLine) ShiftLineNumber(by int)

func (WrappedErrorWLine) Unwrap

func (e WrappedErrorWLine) Unwrap() error

Unwrap gives the error located in e

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL