nanorc

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package nanorc reads GNU nano's syntax-highlighting definitions so nem can colour the languages it has no hand-written lexer for.

nano ships around forty .nanorc files describing C, Python, Rust, shell, YAML and more. They are read from the system at runtime, exactly as nano reads them. Nothing from them is copied into this repository: they are GPL, and vendoring them would put nem's own licensing at issue. A machine without nano installed simply gets no extra languages.

Why the colours are thrown away

A .nanorc rule names a colour - "color brightcyan" - while nem's renderer maps a semantic syntax.Class to a theme style. That indirection is what lets nem carry a light and a dark palette; taking nano's colour literally would hard-code a dark-terminal choice into every rule.

The obvious fix is a colour-to-class table, and it does not work. Measuring the corpus, nano's colours carry no shared meaning across files: strings are red in java.nanorc and green in rust.nanorc, and every common colour is used for keywords in one file and something else in the next. They are per-file aesthetic choices.

So the class is inferred from what a rule's pattern MATCHES rather than from the colour it was given. A pattern listing bare words between word boundaries is keywords; one wrapping a character class in quotes is strings; one running a comment introducer to end-of-line is comments. That is language-agnostic and does not depend on a convention that turns out not to exist.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultDirs

func DefaultDirs() []string

DefaultDirs are searched in order, with later directories winning.

The user's own directory comes last so a hand-written definition replaces the system one for the same language rather than competing with it.

Types

type Lexer

type Lexer struct {
	// contains filtered or unexported fields
}

Lexer applies one Syntax's rules to a line at a time.

It satisfies syntax.Lexer, so a nanorc-described language plugs into the same incremental highlight cache the hand-written lexers use.

func (Lexer) Comment

func (l Lexer) Comment() string

Comment reports the line-comment introducer the .nanorc declared, or "".

func (Lexer) Lex

func (l Lexer) Lex(line []rune, in syntax.State) ([]syntax.Span, syntax.State)

Lex classifies one line.

Rules are applied in the order the .nanorc lists them and each paints over whatever came before, which is nano's own precedence. Painting into a per-rune array rather than collecting spans is what makes that exact: regex matches in these files overlap constantly, and resolving overlaps after the fact would need the same array anyway.

func (Lexer) Name

func (l Lexer) Name() string

Name reports the language, as the .nanorc named it.

type Set

type Set struct {
	// contains filtered or unexported fields
}

Set is the loaded collection of language definitions.

The zero Set matches nothing, which is what a machine without nano installed gets - and is why every caller can use a Set without checking for nil.

func Load

func Load(dirs ...string) (*Set, []error)

Load reads every .nanorc in the given directories.

A missing directory is not an error: most machines will have some of these and not others. Problems with individual files and individual patterns are returned rather than raised, so a caller can report them without one bad file costing the user every other language.

func (*Set) For

func (s *Set) For(path, firstLine string) syntax.Lexer

For returns a lexer for a file, or nil if no definition matches.

firstLine is matched against header patterns, which is how a script with no extension gets highlighted from its shebang. Pass "" when it is not known; extension matching still works.

It returns nil rather than a plain lexer so a caller can tell "no nanorc covers this" from "this is plain text", and keep its own lexers in front.

func (*Set) Len

func (s *Set) Len() int

Len reports how many languages loaded.

func (*Set) Names

func (s *Set) Names() []string

Names lists the loaded languages, sorted.

type Syntax

type Syntax struct {
	Name string
	// Comment is the line-comment introducer the file declares, kept because a
	// future comment-toggle command needs it and nothing else records it.
	Comment string
	// contains filtered or unexported fields
}

Syntax is one language's rules.

func Parse

func Parse(name string, r io.Reader) (*Syntax, []error, error)

Parse reads one .nanorc file.

A pattern that will not compile is skipped on its own: nano's files are third party and a single unsupported regex must not cost a language its other twelve rules. The skipped patterns are returned so a caller can report them without the failure being silent.

Jump to

Keyboard shortcuts

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