first commit

This commit is contained in:
Yehowshua Immanuel 2025-02-12 15:54:12 -05:00
commit 13c1ed7b2a
35 changed files with 3330 additions and 0 deletions

17
.github/workflows/docs.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Build and deploy GH Pages
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3.0.0
- name: build_and_deploy
uses: shalzz/zola-deploy-action@v0.17.2
env:
PAGES_BRANCH: gh-pages
TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.idea/
public

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Vincent Prouillet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
README.md Normal file
View file

@ -0,0 +1,54 @@
# book
A theme based on [Gitbook](https://www.gitbook.com), to write documentation
or books.
![book screenshot](https://github.com/Keats/book/blob/master/screenshot.png?raw=true)
## Contents
- [Installation](#installation)
- [Options](#options)
- [Numbered chapters](#numbered-chapters)
## Installation
First download this theme to your `themes` directory:
```bash
$ cd themes
$ git clone https://github.com/getzola/book.git
```
and then enable it in your `config.toml`:
```toml
theme = "book"
# Optional, if you want search
build_search_index = true
```
## Usage
Book will generate a book from the files you place in the `content` directory. Your book
can have two levels of hierarchy: chapters and subchapters.
Each chapter should be a `section` within the Gutenberg site and should have an `_index.md`
file that sets its `weight` front-matter variable to its chapter number. For example,
chapter 2 should have `weight = 2`. Additionally, each chapter should also set the
`sort_by = "weight"` in its front matter.
Each subchapter should be a `page` and should have its `weight` variable set to the subchapter
number. For example, subchapter 3.4 should have `weight = 4`.
Finally, you should create an `_index.md` file and set the `redirect_to` front-matter variable
to redirect to the first section of your content. For example, if your first section has the
slug `introduction`, then you would set `redirect_to = "introduction"`.
## Options
### Numbered chapters
By default, the `book` theme will number the chapters and pages in the left menu.
You can disable that by setting the `book_number_chapters` in `extra`:
```toml
book_number_chapters = false
```

12
config.toml Normal file
View file

@ -0,0 +1,12 @@
base_url = "https://getzola.github.io/book/"
compile_sass = true
title = "book theme"
description = "A book theme"
build_search_index = true
[markdown]
highlight_code = true
highlight_theme = "css"
[extra]
book_number_chapters = true

3
content/_index.md Normal file
View file

@ -0,0 +1,3 @@
+++
redirect_to = "chapter1"
+++

152
content/chapter1/_index.md Normal file
View file

@ -0,0 +1,152 @@
+++
title = "Introduction"
weight = 1
sort_by = "weight"
insert_anchor_links = "right"
+++
BH (Bluespec Haskell/Classic) is a language for hardware design. The
language borrows its notation, type and package system from an existing
general-purpose functional programming language called Haskell
[@haskell12] where those constructs have been well tested for over a
decade. Unlike Haskell, BH is meant solely for hardware design--- a BH
program represents a circuit. The abstract model for these circuits is a
Term Rewriting System (TRS); details about using TRSs for describing
circuits, and compiling these descriptions to real hardware, may be
found in James Hoe's thesis [@jhoe]. BH has several restrictions and
extensions relative to Haskell, arising out of this hardware focus.
This document is not meant as a tutorial on BH (separate documents exist
for that purpose). Nevertheless, this document has numerous small
examples to explicate BH notation.
## Meta notation
The grammar rules in the presentation below mostly follow the usual EBNF
(Extended BNF) structure. Grammar alternatives are separated by
"$\mid$". Items enclosed in \[ \] are optional. Items enclosed in { }
can be repeated zero or more times. The last piece of notation is used
sloppily; sometimes there must be at least one item, and also, the last
terminal inside the { } is sometimes a separator rather than terminator.
## Identifiers and the rôle of upper and lower case
An identifier in BH consists of a letter followed by zero or more
letters, digits, underscores and single quotes. Identifiers are case
sensitive: `glurph`, `gluRph` and `Glurph` are three distinct
identifiers.
The case of the first letter in an identifier is very important. If the
first letter is lower case, the identifier is a "variable identifier",
referred to in the grammar rules as a *varId*. If the first letter is
upper case, the identifier is a "constructor identifier", referred to in
the grammar rules as a *conId*.
In BH, package names (*packageId*), type names (*tycon*) and value
constructor names are all constructor identifiers. (Ordinary) variables,
field names and type variables are all variable identifiers.
A lone underscore, "` `", is treated as a special identifier--- it is
used as a "don't care" pattern or expression (more details in Sections
[5.10](fixme) and
[6.1](fixme)).
## The Standard Prelude
The Standard Prelude is a predefined package that is imported implicitly
into every BH package. It contains a number of useful predefined
entities (types, values/functions, classes, instances, etc.). It is
somewhat analogous to the combination of various ".h" files and standard
libraries in C, except that in BH no special action is needed to import
the prelude or to link it in. We will refer to the prelude periodically
in the following sections, and there are more details in appendix
[15](fixme).
## Lexical syntax/layout
In BH, there are various syntactic constructs that involve zero or more
items enclosed in braces and separated by semicolons: These braces and semicolons can be omitted
entirely if the components are laid out with proper indentation.
Suppose the parser discovers a missing open brace (e.g., after the
keywords `where`, `let`, `do` and `of`). Then, the indentation of the
next lexical element is remembered (and the missing open brace is
implicitly inserted before it). For each subsequent line, if it contains
only whitespace or is indented more, then it is treated as a
continuation of the current item. If it is indented the same amount, it
is treated as the beginning of the next item (*i.e.,* a semicolon is
inserted implicitly before the item). If it is indented less, then the
list of items is considered to be complete (*i.e.,* a closing brace is
implicitly inserted). An explicit brace is never matched against an
implicit one. Thus, while using the layout rule, if the parser
encounters an explicit open brace, then it does not resume using the
layout rule for this list of items until it has "emerged" past the
explicit corresponding closing brace (a construct nested inside this
list of items may still use the layout rule).
## Comments in BH programs
In a BH program, a *comment* is legal as whitespace, and may be
introduced in two ways. An *ordinary comment* is introduced by a lexical
token consisting of two or more consecutive dashes followed by a
non-symbol, and extends up to and including the end of the line. (See
Section
[\[sec-infix-applications\]](fixme) for the list of symbols.) Note: the
lexical token `—>` is a legal token in BH, and since it contains three
consecutive dashes followed by a symbol, it does not begin a comment.
A *nested comment* is introduced by the lexeme "`{-`" and extends until
the next matching "`-}`", possibly spanning multiple lines. A nested
comment can itself contain another nested comment; this nesting can be
repeated to any depth.
In an ordinary comment, the character sequences "`{-`" and "`-}`" have
no special significance, and, in a nested comment, a sequence of dashes
has no special significance.
## General organization of this document
A concept that is pervasive in BH is the notion of a *type*. Every value
expression in BH, even a basic value identifier, has a type, and the
compiler does extensive static type checking to rule out absurd use of
values (such as taking the square root of an IP address). Types are
discussed in section [2](fixme).
A BH program consists of one or more packages. These outermost
constructs are described in section
[3](fixme). As
explained later, a BH package is a linguistic namespace-management
mechanism and does not have any direct correlation with any hardware
module being described by the program. Hardware modules correspond to
*modules*, a particular type of value in BH.
Within each package is a collection of top-level definitions. These are
described in section [4](fixme).
Amongst the top-level definitions are *value definitions* (section
[4.7](fixme)),
which constitute the actual meat of the code. Value definitions are
built around *expressions*, which are described in section
[5](fixme).

103
content/chapter2/_index.md Normal file
View file

@ -0,0 +1,103 @@
+++
title = "Types"
weight = 2
sort_by = "weight"
insert_anchor_links = "right"
+++
Every value expression and, in particular, every value identifier in BH
has a *type*. In some cases the programmer must supply a *type
signature* specifying this and in many cases the compiler infers it
automatically. The BH programmer should be aware of types at all times.
```
type ::= btype [ "->" type ]
btype ::= [ btype ] atype
atype ::= tycon | tyvar | ( { type , } )
tycon ::= conId
```
Most type expressions have the form: *TypeConstructor* $t_1$ $\cdots$
$t_n$ where $t_1$ $\cdots$ $t_n$ are themselves type expressions, and $n
{\geq} 0$. The $t_1$ $\cdots$ $t_n$ are referred to as the *type
arguments* to the type constructor. $n$ is also called the *arity* of
the type constructor.
Familiar basic types have zero-arity type constructors (no type
arguments, $n = 0$). Examples:
- `Integer`
- `Bool`
- `String`
- `Action`
Other type constructors have arity $n > 0$; these are also known as
*parameterized types*.
Examples:
- `List Bool`
- `List (List Bool)`
- `Array Integer String`
- `Maybe Integer`
These represent the types of lists of
Booleans, lists of lists of Booleans, arrays indexed by integers and
containing strings, and an optional result possibly containing an
integer.
A type can be *polymorphic*, indicated using type variables. Examples:
- `List a`
- `List (Llist b)`
- `Array i (List String)`
These represent lists of things of some unknown type "`a`", lists of
lists of things of some unknown type "`b`", and arrays indexed by some
unknown type "`i`" and containing lists of strings.
One type constructor is given special status in the syntax. The type of
functions from arguments of type $t_1$ to results of type $t_2$ could
have been written as:
Function $t_1$ $t_2$
but in BH we write the constructor as an infix arrow:
$t_1$ -\> $t_2$
These associate to the right, *i.e.,*
$t_1$ -\> $\cdots$ -\> $t_{n-1}$ -\> $t_n$ $\equiv$ $t_1$
-\> ($\cdots$ -\> ($t_{n-1}$ -\> $t_n$))
There is one particular set of niladic type constructors that look like
numbers. These are used to represent certain "sizes". For example, the
type:
`Bit 16`
consists of the unary type constructor `Bit` applied to type represented
by the niladic type constructor "`16`". The type as a whole represents
bit vectors of length 16 bits. Similarly the type
`UInt 32`
represents the type of unsigned integers that can be represented in 32
bits. These numeric types are said to have kind `#`, rather than kind
`*` for value types.
Strings can also be used as type, having kind `$`. This is less common,
but string types are quite useful in the generics library, described in
the *Libraries Reference Guide*. Examples:
- `MetaData#("Prelude","Maybe",PrimUnit,2)`
- `MetaConsNamed#("Valid",1,1)`

108
content/chapter2/page1.md Normal file
View file

@ -0,0 +1,108 @@
+++
title = "Type classes and overloading"
weight = 1
+++
BH's `class` and `instance` mechanisms form a systematic way to do
*overloading* (the approach has been well tested in Haskell).
Overloading is a way to use a common name to refer to a set of
operations at different types. For example, we may want to use the "`<`"
operator name for the integer comparison operation, the floating-point
comparison operation, the vector comparison operation and the matrix
comparison operation. Note that this is not the same as polymorphism: a
polymorphic function is a *single* function that is meaningful at an
infinity of types (*i.e.,* at every possible instantiation of the type
variables in its type). An overloaded identifier, on the other hand,
usually uses a common name to refer to a (usually) small set of distinct
operations.
Further, it may make sense to have "`<=`", "`>`" and "`>=`" operations
wherever there is a "`<`" operation, on integers, floating points
numbers, vectors and matrices. Rather than handle these separately, we
say:
- there is class of types which we will call `Ord` (for "ordered types"),
- that the integer, floating point, vector and matrix types are members
(or "instances") of this class, and
- that all types that are members of this class have appropriate
definitions for the "`<`", "`<=`", "`>`" and "`>=`" operations. We also
say that these operations are *overloaded* across these instance types,
and we refer to these operations as the *methods* of this class.
Another example: we could use a class `Hashable` with an operation
called `hash` to represent those types $T$ for which we can and do
define a hashing function. Each such type $T$ has to specify how to
compute the `hash` function at that type.
Classes, and the membership of a type in a class, do not come into
existence by magic. Every class is created explicitly using a class
declaration, described in section
[4.5](fixme).
A type must explicitly be made an instance of a class and the
corresponding class methods have to be provided explicitly; this is
described in [4.6](fixme).
### Context-qualified types
Consider the following type declaration:
```hs
sort :: (Ord a) => List a -> List a
```
It expresses the idea that a sorting function takes an (unsorted) input
list of items and produces a (sorted) output list of items, but it is
only meaningful for those types of items ("`a`") for which the ordering
functions (such as "`<`") are defined. Thus, it is ok to apply `sort` to
lists of `Integer`'s or lists of `Bool`'s, because those types are
instances of `Ord`, but it is not ok to apply `sort` to a list of, say,
`Counter`'s (assuming `Counter` is not an instance of the `Ord` class).
In the type of `sort` above, the part before "`=>`" is called a
*context*. A context expresses constraints on one or more type
variables--- in the above example, the constraint is that any actual
type "`a`" must be an instance of the `Ord` class.
A context-qualified type has the following grammar:
```
ctxType ::= [ context => ] type
context ::= ( {classId { varId }, })
classId ::= conId
```
In the above example, the class `Ord` had only one type parameter
(*i.e.,* it constrains a single type) but, in general, a type class can
have multiple type parameters. For example, in BH we frequently use the
class "`Bits a n`" which constrains the type represented by `a` to be
representable in bit strings of length represented by the type `n`.
> **NOTE:**
>
> When using an overloaded identifier `x` there is always a question of
> whether or not there is enough type information available to the
> compiler to determine which of the overloaded `x`'s you mean. For
> example, if `read` is an overloaded function that takes strings to
> integers or Booleans, and `show` is an overloaded function that takes
> integers or Booleans to strings, then the expression `show (read s)` is
> ambiguous--- is the thing to be read an integer or a Boolean?
>
> In such ambiguous situations, the compiler will so notify you, and you
> may need to give it a little help by inserting an explicit type
> signature, e.g.,
>
> ```hs
> show ((read s) :: Bool)
> ```

View file

@ -0,0 +1,82 @@
+++
title = "Packages"
weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
Packages are the outermost constructs in BH--- all BH code must be
inside packages. There should be one package per file. A BH package is a
linguistic device for namespace control, and is particularly useful for
programming-in-the-large. A package does not directly correspond to
hardware modules. (Hardware modules correspond to BH modules, described
in section [5.13](fixme))
A BH package consists of the package header, import declarations, and
top level definitions. The package header indicates which names defined
in this package are exported, *i.e.,* available for import into other
packages.
```
packageDefn ::= package packageId ( exportDecl ) where {
{ importDecl ; }
{ fixityDecl ; }
{ topDefn ; }
}
exportDecl ::= varId |typeId [ conList ]
conList ::= (..)
importDecl ::= import [ qualified ] packageId
fixityDecl ::= fixity integer varId
fixity ::= infix |infixl |infixr
packageId ::= conId
```
Example:
```hs
package Foo (x, y) where
import Bar
import Glurph
-- top level definition ...
-- top level definition ...
-- top level definition ...
```
Here, `Foo` is the name of this package, `x` and `y`
are names exported from this package (they will be defined amongst the
top level definitions in this package), and `Bar` and `Glurph` are the
names of package being imported (for use in this package).
The export list is a list of identifiers, each optionally followed by
`(..)`. Each identifier in the list will be visible outside the package.
If the exported identifier is the name of `data`, `struct`, or
`interface`, then the constructors or fields of the type will be visible
only if `(..)` is used. Otherwise, if you export only the name of a type
without the `(..)` suffix, the type is an abstract (opaque) data type
outside the package. The list of identifiers may include identifiers
defined in the package as well as identifiers imported from other
packages.
If the keyword `qualified` is present in the import declaration all the
imported entities from that package must be referred to by a qualified
name.
The fixity declaration can be used to give a precedence level to a
user-defined infix operator. The `infixl` specifies a left associative
operator, `infixr` a right associative operator, and `infix` a
non-associative operator.
## Name clashes and qualified names
When used in any scope, a name must have an unambiguous meaning. If
there is name clash for a name $x$ because it is defined in the current
package and/or it is available from one or more imported packages, then
the ambiguity can be resolved by using a qualified name of the form
$M.x$ to refer to the version of $x$ contained in package $M$.

View file

@ -0,0 +1,12 @@
+++
title = "Top Level Definitions"
weight = 4
sort_by = "weight"
insert_anchor_links = "right"
+++
# Top level definitions
Top level definitions can be used only on the top level within a
package.

146
content/chapter4/page1.md Normal file
View file

@ -0,0 +1,146 @@
+++
title = "`data`"
weight = 1
+++
A `data` definition defines a brand new type, which is different from
every primitive type and every other type defined using a `data`
definition, even if they look structurally similar. The new type defined
by a `data` definition is a "sum of products", or a "union of products".
```
topDefn ::= data typeId {tyVarId } = {summand | }[ derive ]
summand ::= conId {type }
summand ::= conId { { fieldDef ; }}
derive ::= deriving ( { classId , })
fieldDef ::= fieldId :: type
```
The *typeId* is the name of this new type. If the *tyVarId*'s exist,
they are type parameters, thereby making this new type polymorphic. In
each *summand*, the *conId* is called a "constructor". You can think of
them as unique *tag*'s that identify each summand. Each *conId* is
followed by a specification for the fields involved in that summand
(*i.e.,* the fields are the "product" within the summand). In the first
way of specifying a summand, the fields are just identified by position,
hence we only specify the types of the fields. In the second way of
specifying a summand, the fields are named, hence we specify the field
names (*fieldId*'s) and their types.
The same constructor name may occur in more than one type. The same
field name can occur in more than one type. The same field name can
occur in more than one summand within the same type, but the type of the
field must be the same in each summand.
The optional *derive* clause is used as a shorthand to make this new
type an instance of the *classId*'s, instead of using a separate,
full-blown `instance` declaration. This can only be done for certain
predefined *classId*'s: `Bits`, `Eq`, and `Bounded`. The compiler
automatically derives the operations corresponding to those classes
(such as `pack` and `unpack` for the `Bits` class). Type classes,
instances, and `deriving` are described in more detail in sections
[2.1](fixme), [4.5](fixme) and [
4.6](fixme).
To construct a value corresponding to some `data` definition $T$, one
simply applies the constructor to the appropriate number of arguments
(see section [5.3](fixme){reference-type="ref"
reference="sec-exprs-constrs"}); the values of those arguments become
the components/fields of the data structure.
To extract a component/field from such a value, one uses pattern
matching (see section [6](fixme){reference-type="ref"
reference="sec-patterns"}).
Example:
```hs
data Bool = False | True
```
This is a "trivial" case of a `data` definition. The type is not
polymorphic (no type parameters); there are two summands with
constructors `False` and `True`, and neither constructor has any fields.
It is a 2-way sum of empty products. A value of type `Bool` is either
the value `False` or the value `True` Definitions like these correspond
to an "enum" definition in C.
Example:
```hs
data Operand = Register (Bit 5)
| Literal (Bit 22)
| Indexed (Bit 5) (Bit 5)
```
Here, the first two summands have one field each; the third has two
fields. The fields are positional (no field names). The field of a
`Register` value must have type Bit 5. A value of type `Operand` is
either a `Register` containing a 5-bit value, or a `Literal` containing
a 22-bit value, or an `Indexed` containing two 5-bit values.
Example:
```hs
data Maybe a = Nothing | Just a
deriving (Eq, Bits)
```
This is a very useful and commonly used type. Consider a function that,
given a key, looks up a table and returns some value associated with
that key. Such a function can return either `Nothing`, if the table does
not contain an entry for the given key, of `Just `$v$, if the table
contains $v$ associated with the key. The type is polymorphic (type
parameter "`a`") because it may be used with lookup functions for
integer tables, string tables, IP address tables, etc., *i.e.,* we do
not want here to over-specify the type of the value $v$ at which it may
be used.
Example:
```hs
data Instruction = Immediate { op::Op; rs::Reg; rt::CPUReg; imm::UInt16; }
| Jump { op::Op; target::UInt26; }
```
An `Instruction` is either an `Immediate` or a `Jump`. In the former
case, it contains a field called `op` containing a value of type `Op`, a
field called `rs` containing a value of type `Reg`, a field called `rt`
containing a value of type `CPUReg`, and a field called `imm` containing
a value of type `UInt16`. In the latter case, it contains a field called
`op` containing a value of type `Op`, and a field called `target`
containing a value of type `UInt26`.
> **NOTE:**
>
> Error messages involving data type definitions sometimes show traces of
> how they are handled internally. Data type definitions are translated
> into a data type where each constructor has exactly one argument. The
> types above translate to:
>
> ```hs
> data Bool = False PrimUnit | True PrimUnit
>
> data Operand = Register (Bit 5)
> | Literal (Bit 22)
> | Indexed Operand_$Indexed
> struct Operand_$Indexed = { _1 :: Reg 5; _2 :: Reg 5 }
>
> data Maybe a = Nothing PrimUnit | Just a
>
> data Instruction = Immediate Instruction_$Immediate
> | Register Instruction_$Register
>
> struct Instruction_$Immediate = { op::Op; rs::Reg; rt::CPUReg; imm::UInt16; }
> struct Instruction_$Register = { op::Op; target::UInt26; }
> ```

68
content/chapter4/page2.md Normal file
View file

@ -0,0 +1,68 @@
+++
title = "`struct`"
weight = 1
+++
Defines a record type (a "pure product"). This is a specialized form of
a `data` definition. The same field name may occur in more than one
type.
```
topDefn ::= struct typeId {tyVarId }= { { fieldDef ; }} [ derive ]
fieldDef ::= fieldId :: type
```
Example:
```
struct Proc = { pc :: Addr; rf :: RegFile; mem :: Memory }
struct Coord = { x :: Int; y :: Int }
```
Section [5.6](fixme) describes how to construct values of a
`struct` type. A field of a `struct` type can be extracted either
directly using "dot" notation (section
[5.7](fixme)) or using pattern matching (section
[6.3](fixme)).
### Tuples {#sec-tuple-type}
One way to group multiple values together is to use a `data` definition
in which a constructor has multiple fields.
However, there is a built-in notation for a common form of grouping,
called "tuples". To group two (or more) values together the Prelude
contains a type, `PrimPair`, for which there is syntactic sugar for type
expressions, value expressions, and patterns.
The type has the following definition
```hs
struct PrimPair a b = { fst :: a; snd :: b } deriving (Eq, Bits, Bounded)
```
For type expressions the following shorthand can be used:
(a, b) $\equiv$ PrimPair a b
Or, more generally,
($t_1$, $t_2$, $\cdots$, $t_n$) $\equiv$ PrimPair $t_1$ (PrimPair $t_2$ ($\cdots$ $t_n$))
There is a corresponding shorthand for value expressions and patterns:
(a, b) $\equiv$ PrimPair { fst = a; snd = b }
There is also special syntax for the empty tuple. It is written "`()`"
for types, expressions, and patterns. The real type has the following
definition
```hs
struct PrimUnit = { } deriving (Eq, Bits, Bounded)
```

38
content/chapter4/page3.md Normal file
View file

@ -0,0 +1,38 @@
+++
title = "`type`"
weight = 1
+++
Defines a type synonym. These are used purely for readability, *i.e.,* a
type synonym can always be "expanded out" to its definition at any time.
```
topDefn ::= type typeId {tyVarId }= type
```
Examples:
```hs
type Byte = Bit 8
type Word = Bit 16
type LongWord = Bit 32
```
These provide commonly used names for certain bit lengths. In a
specification of a processor:
```hs
data RegName = R0 | R1 | ... | R31
type Rdest = RegName
type Rsrc = RegName
data ArithInstr = Add Rdest Rsrc Rsrc
| Sub Rdest Rsrc Rsrc
```
the last two lines suggest the roles of the registers in the
instructions, and is more readable than:
```hs
data ArithInstr = Add RegName RegName RegName
| Sub RegName RegName RegName
```

43
content/chapter4/page4.md Normal file
View file

@ -0,0 +1,43 @@
+++
title = "`interface`"
weight = 1
+++
Defines an interface for a hardware module (see section
[5.13](fixme)). An
interface is essentially a `struct`, but its components are restricted
to those things that have a physical interpretation as wires in and out
of a circuit. The types of fields in an interface are more likely to
involve `Action`'s (see section
[5.11](fixme)),
which are typically interpreted as "enable signals" into a circuit. The
fields of an interface are also known as *methods* (not to be confused
with methods of a class, described in Sections
[2.1](fixme) and
[4.5](fixme)).
```
topDefn ::= interface typeId {tyVarId }= { { fieldDef ; }}
```
Example:
```hs
interface Stack a =
push :: a -> Action
pop :: Action
top :: Maybe a
```
This describes a circuit that implements a stack (a LIFO) of items. This
polymorphic definition does not specify the type of the contents of the
stack, just that they have some type "`a`". Corresponding to the `push`
method, the circuit will have input wires to carry a value of type
"`a`", and a "push-enable" input wire that specifies when the value
present on the input wires should be pushed on the stack. Corresponding
to the `pop` component, the circuit will have a "pop-enable" input wire
that specifies when a value should be popped off the stack.
Corresponding to the `top` component, the circuit will have a set of
output wires: if the stack is empty, the wires will represent the value
`Nothing`, and if the stack is non-empty and $v$ is the value at the top
of the stack, the wires will represent `Maybe` $v$.

86
content/chapter4/page5.md Normal file
View file

@ -0,0 +1,86 @@
+++
title = "`class` declarations"
weight = 1
+++
The general concepts behind classes, instances, overloading etc. were
introduced in section [2.1](fixme). A new class is declared using the
following:
```
topDefn ::= class [ context => ] classId {tyVarId }[ | funDep ] where {
{varId :: ctxType ; }
}
```
*classId* is the newly declared class. It can be polymorphic, if
*tyVarId*'s exist; these are called the *parameters* of the type class.
The *tyVarId*'s may themselves be constrained by *context*, in which
case the classes named in *context* are called the "super-classes" of
this class. The "*varId*`::`*ctxType*" list declares the class method
names and their types.
Example (from the Prelude):
```hs
class Literal a where
fromInteger :: Integer -> a
```
This defines the class `Literal`. It says that any type `a` in this
class must have a method (a function) called `fromInteger` that converts
an `Integer` value into the type `a`. In fact, this is the mechanism the
BH uses to interpret literal constants, e.g., to resolve whether a
literal like `6`847 is to be interpreted as a signed integer, an
unsigned integer, a floating point number, a bit value of 10 bits, a bit
value of 8 bits, etc. (This is described in more detail in Section
[5.3](fixme).)
Example (from the Prelude):
```hs
class (Literal a) => Arith a where
(+) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
(*) :: a -> a -> a
```
This defines the class `Arith` with super-class `Literal`. It says that
for any type `a` that is a member of the class `Arith`, it must also be
a member of the class `Literal`, and it must have four methods with the
given names and types. Said another way, an `Arith` type must have a way
to convert integer literals into that type, and it must have addition,
subtraction, negation and multiplication defined on it.
The optional *funDep* section specifies *functional dependencies*
between the parameters of the type class:
```
funDep ::= { {tyVarId }-> {tyVarId }, }
```
These declarations specify that a type parameter may be determined
uniquely by certain other type parameters. For example:
```hs
class Add x y z | x y -> z, y z -> x, z x -> y
```
Here, the class declaration says that for any triple of types `x`, `y`
and `z` that are in the class `Add`, any two of the types uniquely
determines the remaining type, *i.e.,*
- x and y uniquely determine z,
- y and z uniquely determine x, and
- z and z uniquely determine y.
See section [8.1](fixme) for more detailed insights into
the use of functional dependencies.
> **NOTE:**
> Functional dependencies are not currently checked by the compiler.

113
content/chapter4/page6.md Normal file
View file

@ -0,0 +1,113 @@
+++
title = "`instance` declarations"
weight = 1
+++
A type can be declared as an instance of a class in two ways. The
general mechanism is the `instance` declaration; a convenient shortcut
that can sometimes be used is the `deriving` mechanism.
The general `instance` declaration grammar is the following:
```
topDefn ::= instance context => classId {type }where
{ {localDefn ; }}
```
This can be read as saying that the type *type* is an instance of class
*classId*, provided the constraints of *context* hold, and where the
*localDefn*'s specify the implementation of the methods of the class.
Sometimes, when a new type is defined using a `data` declaration, it can
simultaneously be made a member of certain useful, predefined classes,
allowing the compiler to choose the "obvious" implementation of the
class methods. This is done using the `deriving` qualification to a
`data` declaration (described in section
[4.1](fixme)) or to a
`struct` declaration (described in section
[4.2](fixme)). The only classes for which `deriving` can
be used for general types are `Bits`, `Eq` and `Bounded`. Furthermore,
`deriving` can be used for any class if the type is a data type that is
isomorphic to a type that has an instance for the derived class.
### Deriving `Bits` {#sec-deriving-Bits}
The instances derived for the `Bits` class can be described as follows:
- For a `struct` type it is simply the the concatenation of the bits for
all the fields. The first field is in the leftmost (most significant)
bits, and so on.
- For a `data` type, all values of the type occupy the same number of
bits, regardless of which disjunct (constructor) it belongs to. This
size is determined by the largest disjunct. The leftmost (most
significant) bits are a code (a tag) for the constructor. As few bits as
possible are used for this. The first constructor in the definition is
coded 0, the next constructor is coded 1, and so on. The size of the
rest of the bits is determined by the largest numbers of bits needed to
encode the fields for the constructors. For each constructor, the fields
are laid out left to right, and the concatenated bits are stored right
justified (*i.e.,* at the least significant bits). For disjuncts that
are smaller than the largest one, the bits between the constructor code
and the field bits, if any, are "don't care" bits.
Examples: The type
```hs
data Bool = False | True
```
uses one bit. `False` is represented by 0 and `True` by 1.
```hs
struct Två = { första :: Bit 8; andra:: Bit 16 }
```
uses 24 bits with `första` in the upper 8 bits and `andra`
in the lower 16.
```hs
data Maybe a = Nothing | Just
```
a will use $1+n$ bits,
where $n$ bits are needed to represent values of type `a`. The extra bit
will be the most significant bit and it will be 0 (followed by $n$
unspecified bits) for `Nothing` and 1 (followed by the $n$ bits for `a`)
for `Just`.
### Deriving `Eq`
The instances derived for the `Eq` class is the natural equality for the
type. For a struct all fields have to be equal, for a data type the
constructors have to be equal and then all their parts.
### Deriving `Bounded`
An instance for `Bounded` can be derived for an enumeration type,
*i.e.,* a data type where all constructors are niladic. The `minBound`
will be the first constructor and the `maxBound` will be the last.
`Bounded` can also be derived for a `struct` type if all the field types
of the struct are `Bounded`. The `minBound` will be the struct with all
fields having their respective `minBound`, and correspondingly for
`maxBound`.
### Deriving for isomorphic types
A data type with one constructor and one argument is isomorphic to its
type argument. For such a type any one-parameter class can be used, in a
`deriving`, for which there is an instance for the underlying type.
Example:
```hs
data Apples = Apple (UInt 32) deriving (Literal, Arith)
five :: Apples
five = 5
eatApple :: Apples -\> Apples
eatApple n = n - 1
```

94
content/chapter4/page7.md Normal file
View file

@ -0,0 +1,94 @@
+++
title = "Value definitions"
weight = 1
+++
A value definition defines the value of an identifier (which could be a
function). Value definitions are the meat of a BH program.
Value definitions consist of a type signature followed immediately by
one or more defining clauses:
```
topDefn ::= valueDefn
valueDefn ::= varId :: ctxType ;
{clause ; }
clause ::= varId
{apat }[ when guard ]= exp
```
The first line of a value definition is the type signature--- it simply
specifies that the identifier *varId* has the type *ctxType*. Subsequent
lines define the value, one clause at a time. The *varId*'s on the
left-hand side of the type signature and on the left-hand side of each
clause must all be the same, *i.e.,* they collectively define a single
*varId*.
Each clause defines part of the value, using pattern matching and
guards. If there are patterns (*apat*'s) present, then the *varId* being
defined is a function, and the patterns represent arguments to the
function. The *guard* is a list of arbitrary predicates that may use
identifiers bound in the patterns (see Section [7](fixme)).
The clause should be read as follows: if the function *varId* is applied to
arguments that match the corresponding *apat*'s (in which case,
identifiers in the *apat*'s are bound to the corresponding components of
the arguments), and if the predicates in the *guard* are true, then the
function returns the value of the expression *exp*.
Example:
```hs
wordSize :: Integer
wordSize = 16
```
This simply defines the identifier `wordSize` to have type `Integer` and
value 16.
Example:
```hs
not :: Bool -> Bool
not True = False
not False = True
```
This defines the classical Boolean negation function. The type signature
specifies that `not` is a function with argument type `Bool` and result
type `Bool`. After that, the first clause specifies that if the argument
matches the value `True` (*i.e.,* it *is* the value `True`), then it
returns `False`. The final clause specifies that if the argument is
`False` it returns `True`.
Example:
```hs
f :: Maybe Int -> Int -> Int
f (Just x) y when x > 10, Just y <- g y = x + y'
f _ _ = 0
```
(If necessary, please first remember the definition of the `Maybe` type,
introduced in section [4.1](fixme)). The first line specifies that
`f` is a function
of two arguments, of type `Maybe Int` and `Int`, respectively, and that
its result has type `Int`. The second line specifies that if the first
argument has the form `Just x` (in which case let us call its component
`x`), if the second argument is anything (let us call it `y`), if `x`'s
value is greater than 10, if the result of applying `g` to `y` has the
form `Just y` (in which case let us call the component `y`), then the
result is the value of `x + y`. In all other cases, the result is the
value 0. The bare underscores in the second line are *wild-card*
patterns that match anything (described in section
[6.1](fixme)).
Clauses are attempted in order, from top to bottom, proceeding to the
next clause only if the pattern matching and guard evaluation fail.
Within each clause, pattern matching and guard evaluation are attempted
from left to right. If no clause succeeds, then the system will raise a
"pattern matching error".

46
content/chapter4/page8.md Normal file
View file

@ -0,0 +1,46 @@
+++
title = "Calling foreign functions"
weight = 1
+++
A function can be declared to be foreign which means that its
implementation is not in BH.
```
topDefn ::= foreign varId :: type [= string ] [ , ( {string }) ]
```
The optional string gives the name of the external "function" to use. If
no string is given the same name as the BH name is used. The optional
strings in parentheses are the port names of the Verilog module that
implements the function. Without port names positional arguments will be
used.
Example:
```hs
foreign countOnes :: Bit n -> Bit 32 = "pop_count"
```
A call to `countOnes` will instantiate the Verilog `pop`` ``count`
module. It should have the same number of arguments (with the same type)
as the BH function, *and* an additional trailing argument which is the
result. If the function is (size) polymorphic the instantiated types
will be used as Verilog parameters.
Example: using the declaration above an action, with the type of `x`
being `Bit 5`,
```hs
y := countOnes x
```
will translate to something like
```hs
pop_count #(5) ires1(R_x, I_y);
```

21
content/preface/_index.md Normal file
View file

@ -0,0 +1,21 @@
+++
title = "UNDER CONSTRUCTION ⚠️"
weight = 5
sort_by = "weight"
insert_anchor_links = "right"
+++
> Note that these docs are under construction and may not be finished
> until summer 2025!
> There are several chapters remaining to complete!
This is a largely manual attempt(with much assistance from
[Pandoc][pandoc]) to convert the
[Bluespec Haskell/Classic LaTeX docs][bhdocs] to an online
readable markdown format.
If you find any errors, please reach out to me at
[yehowshua@joyofhardware.com](mailto:yehowshua@joyofhardware.com)
[pandoc]: https://pandoc.org
[bhdocs]: https://github.com/B-Lang-org/bsc/tree/main/doc/BH_ref_guide

231
sass/_content.scss Normal file
View file

@ -0,0 +1,231 @@
@use "variables";
.page {
position: absolute;
width: calc(100% - #{variables.$sidebar-width});
height: 100%;
overflow-y: auto;
color: #000;
background: #fff;
padding-bottom: 20px;
transition: 0.5s;
.zola-anchor {
color: #357aba;
padding-left: 10px;
text-decoration: none;
font-weight: initial;
&:hover {
text-decoration: underline;
}
}
img {
max-width: 100%;
}
&__content {
a {
color: #357aba;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
hr {
height: 4px;
padding: 0;
margin: 1.7em 0;
overflow: hidden;
background-color: #e7e7e7;
border: none;
}
pre {
padding: 1rem;
span {
white-space: pre-wrap;
}
}
blockquote {
margin: 0;
margin-bottom: .85em;
padding: 0 15px;
color: #858585;
border-left: 4px solid #e5e5e5;
}
pre code {
background: none;
}
code {
display: inline-block;
vertical-align: middle;
padding: 0.1em 0.3em;
border-radius: 3px;
color: #6e6b5e;
background: #f1f1f1;
font-size: 0.875em;
font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
}
iframe {
border: 0;
}
table {
margin: 0 auto;
border-collapse: collapse;
border-color: #cccccc;
td {
padding: 3px 20px;
border: 1px solid #ccc;
}
thead {
th {
padding: 6px 13px;
font-weight: bold;
border: 1px solid #ccc;
}
}
}
font-size: 1.6rem;
word-wrap: break-word;
line-height: 1.7;
position: relative;
left: 0;
max-width: 800px;
margin: 0 auto;
padding: 0 15px 40px;
p {
margin-top: 0;
margin-bottom: 0.85em;
}
}
.previous, .next {
position: fixed;
display: flex;
top: 50px;
bottom: 0;
font-size: 2.5em;
color: #ccc;
text-decoration: none;
text-align: center;
margin: 0;
max-width: 150px;
min-width: 90px;
justify-content: center;
align-content: center;
flex-direction: column;
&:hover {
color: #333;
}
}
.previous {
left: variables.$sidebar-width;
float: left;
transition: left 0.5s;
}
.next {
// not 0 as it goes over the sidebar otherwise
right: 15px;
float: right;
}
@include variables.max-screen(1250px) {
.previous, .next {
position: static;
top: auto;
display: inline-block;
max-width: 49%;
width: 49%;
&:hover {
text-decoration: none;
}
}
}
}
@include variables.min-screen(600px) {
.page {
left: variables.$sidebar-width;
}
}
.page-without-menu {
width: 100%;
left: 0;
.previous {
left: 15px;
}
}
@include variables.max-screen(600px) {
.page {
width: 100%;
left: 0;
}
.page-without-menu {
left: calc(100% - 100px);
}
}
.search-container {
display: none;
&--is-visible {
display: block;
}
#search {
width: 100%;
padding: 1rem;
border: 1px solid #aaa;
border-radius: 3px;
background-color: #fafafa;
color: #000;
}
.search-results {
&__header {
font-weight: bold;
padding: 1rem 0rem;
}
&__items {
margin: 0;
padding: 0;
list-style: none;
}
&__item {
margin-bottom: 1rem;
}
&__teaser {
font-size: 90%;
}
}
}
.search-mode {
.prev-link, .next-link {
display: none;
}
}

18
sass/_document.scss Normal file
View file

@ -0,0 +1,18 @@
* {
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body, html {
height: 100%;
}
body {
text-rendering: optimizeLegibility;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
letter-spacing: 0.2px;
}

160
sass/_header.scss Normal file
View file

@ -0,0 +1,160 @@
@mixin menu-icon() {
@keyframes clickfirst {
0% {
transform: translateY(6px) rotate(0deg);
}
100% {
transform: translateY(0) rotate(45deg);
}
}
@keyframes clickmid {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes clicklast {
0% {
transform: translateY(-6px) rotate(0deg);
}
100% {
transform: translateY(0) rotate(-45deg);
}
}
@keyframes outfirst {
0% {
transform: translateY(0) rotate(-45deg);
}
100% {
transform: translateY(-6px) rotate(0deg);
}
}
@keyframes outmid {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes outlast {
0% {
transform: translateY(0) rotate(45deg);
}
100% {
transform: translateY(6px) rotate(0deg);
}
}
span {
position: absolute;
/* fallback for browsers which still doesn't support for `calc()` */
left: 15px;
top: 25px;
left: calc((100% - 20px) / 2);
top: calc((100% - 1px) / 2);
width: 20px;
height: 2px;
background-color: rgba(0, 0, 0, 0.5);
&:nth-child(1) {
transform: translateY(6px) rotate(0deg);
}
&:nth-child(3) {
transform: translateY(-6px) rotate(0deg);
}
}
&.icon-click {
span:nth-child(1) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: clickfirst;
}
span:nth-child(2) {
animation-duration: 0.2s;
animation-fill-mode: both;
animation-name: clickmid;
}
span:nth-child(3) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: clicklast;
}
}
&.icon-out {
span:nth-child(1) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: outfirst;
}
span:nth-child(2) {
animation-duration: 0.2s;
animation-fill-mode: both;
animation-name: outmid;
}
span:nth-child(3) {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: outlast;
}
}
}
.page__header {
height: 50px;
.menu-icon {
height: 50px;
width: 50px;
font-size: 24px;
text-align: center;
float: left;
position: relative;
transition: background .5s;
cursor: pointer;
@include menu-icon();
&:hover {
span {
background-color: black;
}
}
}
.search-icon {
height: 50px;
width: 50px;
display: inline-block;
text-align: center;
line-height: 50px;
color: rgba(0, 0, 0, 0.5);
cursor: pointer;
font-size: 2rem;
&:hover {
color: black
}
}
}

57
sass/_navigation.scss Normal file
View file

@ -0,0 +1,57 @@
@use "variables";
.menu {
height: 100%;
position: absolute;
left: 0;
overflow-y: auto;
width: 300px;
color: #364149;
background: #fafafa;
border-right: 1px solid rgba(0, 0, 0, 0.07);
transition: 0.5s;
ul {
list-style: none;
margin: 0;
padding: 0;
a {
display: block;
color: #364149;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-decoration: none;
padding: 10px 15px;
&:hover {
text-decoration: underline;
}
}
li.active > a {
color: #0053bc;
text-decoration: none;
}
ul {
padding-left: 20px;
}
}
}
.menu-hidden {
width: 0;
}
@include variables.max-screen(600px) {
.menu {
width: 0;
z-index: 1;
}
.menu-hidden {
width: calc(100% - 100px);
z-index: 0;
}
}

447
sass/_normalize.scss Normal file
View file

@ -0,0 +1,447 @@
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in
* IE on Windows Phone and in iOS.
*/
html {
line-height: 1.15; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
/**
* Add the correct display in IE 9-.
*/
article,
aside,
footer,
header,
nav,
section {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in IE.
*/
figcaption,
figure,
main { /* 1 */
display: block;
}
/**
* Add the correct margin in IE 8.
*/
figure {
margin: 1em 40px;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* 1. Remove the gray background on active links in IE 10.
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
*/
a {
background-color: transparent; /* 1 */
-webkit-text-decoration-skip: objects; /* 2 */
}
/**
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font style in Android 4.3-.
*/
dfn {
font-style: italic;
}
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
audio,
video {
display: inline-block;
}
/**
* Add the correct display in iOS 4-7.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Remove the border on images inside links in IE 10-.
*/
img {
border-style: none;
}
/**
* Hide the overflow in IE.
*/
svg:not(:root) {
overflow: hidden;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers (opinionated).
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
* controls in Android 4.
* 2. Correct the inability to style clickable types in iOS and Safari.
*/
button,
html [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; /* 2 */
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* 1. Add the correct display in IE 9-.
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Remove the default vertical scrollbar in IE.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10-.
* 2. Remove the padding in IE 10-.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in IE 9-.
* 1. Add the correct display in Edge, IE, and Firefox.
*/
details, /* 1 */
menu {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Scripting
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
canvas {
display: inline-block;
}
/**
* Add the correct display in IE.
*/
template {
display: none;
}
/* Hidden
========================================================================== */
/**
* Add the correct display in IE 10-.
*/
[hidden] {
display: none;
}

162
sass/_syntax-charcoal.scss Normal file
View file

@ -0,0 +1,162 @@
@mixin dark {
.z-code {
color: #cccece;
background-color: #191919;
}
.z-comment, .z-punctuation.z-definition.z-comment {
color: #7e8384;
}
.z-variable {
color: #cccece;
}
.z-keyword, .z-storage.z-type, .z-storage.z-modifier {
color: #c594c5;
}
.z-keyword.z-operator, .z-constant.z-other.z-color, .z-punctuation, .z-meta.z-tag, .z-punctuation.z-definition.z-tag, .z-punctuation.z-separator.z-inheritance.z-php, .z-punctuation.z-definition.z-tag.z-html, .z-punctuation.z-definition.z-tag.z-begin.z-html, .z-punctuation.z-definition.z-tag.z-end.z-html, .z-punctuation.z-section.z-embedded, .z-keyword.z-other.z-template, .z-keyword.z-other.z-substitution {
color: #5fb3b3;
}
.z-entity.z-name.z-tag, .z-meta.z-tag.z-sgml, .z-markup.z-deleted.z-git_gutter {
color: #ff7b84;
}
.z-entity.z-name.z-function, .z-meta.z-function-call, .z-variable.z-function, .z-support.z-function, .z-keyword.z-other.z-special-method, .z-meta.z-block-level {
color: #78aade;
}
.z-support.z-other.z-variable, .z-string.z-other.z-link {
color: #fa7e81;
}
.z-constant.z-numeric, .z-constant.z-language, .z-support.z-constant, .z-constant.z-character, .z-variable.z-parameter, .z-keyword.z-other.z-unit {
color: #f99157;
}
.z-string, .z-constant.z-other.z-symbol, .z-constant.z-other.z-key, .z-entity.z-other.z-inherited-class, .z-markup.z-heading, .z-markup.z-inserted.z-git_gutter, .z-meta.z-group.z-braces.z-curly .z-constant.z-other.z-object.z-key.z-js .z-string.z-unquoted.z-label.z-js {
color: #99c794;
}
.z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class, .z-support.z-type, .z-support.z-class, .z-support.z-orther.z-namespace.z-use.z-php, .z-meta.z-use.z-php, .z-support.z-other.z-namespace.z-php, .z-markup.z-changed.z-git_gutter {
color: #fac863;
}
.z-entity.z-name.z-module.z-js, .z-variable.z-import.z-parameter.z-js, .z-variable.z-other.z-class.z-js {
color: #fe7d83;
}
.z-variable.z-language {
color: #fe7d83;
}
.z-entity.z-name.z-method.z-js {
color: #d8dee9;
}
.z-meta.z-class-method.z-js .z-entity.z-name.z-function.z-js, .z-variable.z-function.z-constructor {
color: #d8dee9;
}
.z-entity.z-other.z-attribute-name {
color: #cd91c4;
}
.z-markup.z-inserted {
color: #99c794;
}
.z-markup.z-deleted {
color: #fe7d83;
}
.z-markup.z-changed {
color: #cd91c4;
}
.z-string.z-regexp {
color: #5fb3b3;
}
.z-constant.z-character.z-escape {
color: #5fb3b3;
}
.z-*url*, .z-*link*, .z-*uri* {
text-decoration: underline;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #cf9a87;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #99c794;
}
.z-tag.z-decorator.z-js .z-entity.z-name.z-tag.z-js, .z-tag.z-decorator.z-js .z-punctuation.z-definition.z-tag.z-js {
color: #78aade;
}
.z-source.z-js .z-constant.z-other.z-object.z-key.z-js .z-string.z-unquoted.z-label.z-js {
color: #fe7d83;
}
}
@mixin light {
.z-code {
color: #727373;
background-color: #ffffff;
}
.z-comment, .z-punctuation.z-definition.z-comment {
color: #5f6364;
}
.z-variable {
color: #727373;
}
.z-keyword, .z-storage.z-type, .z-storage.z-modifier {
color: #916392;
}
.z-keyword.z-operator, .z-constant.z-other.z-color, .z-punctuation, .z-meta.z-tag, .z-punctuation.z-definition.z-tag, .z-punctuation.z-separator.z-inheritance.z-php, .z-punctuation.z-definition.z-tag.z-html, .z-punctuation.z-definition.z-tag.z-begin.z-html, .z-punctuation.z-definition.z-tag.z-end.z-html, .z-punctuation.z-section.z-embedded, .z-keyword.z-other.z-template, .z-keyword.z-other.z-substitution {
color: #237e7f;
}
.z-entity.z-name.z-tag, .z-meta.z-tag.z-sgml, .z-markup.z-deleted.z-git_gutter {
color: #ca4251;
}
.z-entity.z-name.z-function, .z-meta.z-function-call, .z-variable.z-function, .z-support.z-function, .z-keyword.z-other.z-special-method, .z-meta.z-block-level {
color: #4076a7;
}
.z-support.z-other.z-variable, .z-string.z-other.z-link {
color: #c14c52;
}
.z-constant.z-numeric, .z-constant.z-language, .z-support.z-constant, .z-constant.z-character, .z-variable.z-parameter, .z-keyword.z-other.z-unit {
color: #b75922;
}
.z-string, .z-constant.z-other.z-symbol, .z-constant.z-other.z-key, .z-entity.z-other.z-inherited-class, .z-markup.z-heading, .z-markup.z-inserted.z-git_gutter, .z-meta.z-group.z-braces.z-curly .z-constant.z-other.z-object.z-key.z-js .z-string.z-unquoted.z-label.z-js {
color: #517c4e;
}
.z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class, .z-support.z-type, .z-support.z-class, .z-support.z-orther.z-namespace.z-use.z-php, .z-meta.z-use.z-php, .z-support.z-other.z-namespace.z-php, .z-markup.z-changed.z-git_gutter {
color: #926c00;
}
.z-entity.z-name.z-module.z-js, .z-variable.z-import.z-parameter.z-js, .z-variable.z-other.z-class.z-js {
color: #cb414d;
}
.z-variable.z-language {
color: #cb414d;
}
.z-entity.z-name.z-method.z-js {
color: #6c727c;
}
.z-meta.z-class-method.z-js .z-entity.z-name.z-function.z-js, .z-variable.z-function.z-constructor {
color: #6c727c;
}
.z-entity.z-other.z-attribute-name {
color: #996091;
}
.z-markup.z-inserted {
color: #517c4e;
}
.z-markup.z-deleted {
color: #cb414d;
}
.z-markup.z-changed {
color: #996091;
}
.z-string.z-regexp {
color: #237e7f;
}
.z-constant.z-character.z-escape {
color: #237e7f;
}
.z-*url*, .z-*link*, .z-*uri* {
text-decoration: underline;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #976756;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #517c4e;
}
.z-tag.z-decorator.z-js .z-entity.z-name.z-tag.z-js, .z-tag.z-decorator.z-js .z-punctuation.z-definition.z-tag.z-js {
color: #4076a7;
}
.z-source.z-js .z-constant.z-other.z-object.z-key.z-js .z-string.z-unquoted.z-label.z-js {
color: #cb414d;
}
}

551
sass/_syntax.scss Normal file
View file

@ -0,0 +1,551 @@
@mixin dark {
.z-code {
color: #bfbab0;
background-color: #191919;
}
.z-comment, .z-punctuation.z-definition.z-comment {
color: #87929f;
font-style: italic;
}
.z-variable {
color: #bfbab0;
}
.z-string, .z-constant.z-other.z-symbol {
color: #c2d94c;
}
.z-constant.z-numeric {
color: #f29718;
}
.z-string.z-regexp, .z-constant.z-character.z-escape {
color: #95e6cb;
}
.z-constant.z-language {
color: #f29718;
}
.z-constant.z-character, .z-constant.z-other {
color: #f29718;
}
.z-variable.z-member {
color: #fe7d83;
}
.z-keyword, .z-keyword.z-operator.z-word {
color: #00bbff;
}
.z-keyword.z-operator {
color: #f29668;
}
.z-punctuation.z-separator, .z-punctuation.z-terminator {
color: #bfbab0;
}
.z-punctuation.z-section {
color: #bfbab0;
}
.z-punctuation.z-accessor {
color: #f29668;
}
.z-punctuation.z-definition.z-annotation {
color: #bfbab0;
}
.z-variable.z-other.z-dollar.z-only.z-js, .z-variable.z-other.z-object.z-dollar.z-only.z-js, .z-variable.z-type.z-dollar.z-only.z-js, .z-support.z-class.z-dollar.z-only.z-js {
color: #e6b673;
}
.z-storage {
color: #00bbff;
}
.z-storage.z-type {
color: #00bbff;
}
.z-entity.z-name.z-function {
color: #ffb454;
}
.z-entity.z-name, .z-entity.z-name.z-tag, .z-entity.z-name.z-label {
color: #59c2ff;
}
.z-entity.z-other.z-inherited-class {
color: #59c2ff;
text-decoration: underline;
}
.z-variable.z-parameter {
color: #f29718;
}
.z-variable.z-language {
color: #39bae6;
font-style: italic;
}
.z-entity.z-name.z-tag, .z-meta.z-tag.z-sgml {
color: #39bae6;
}
.z-punctuation.z-definition.z-tag.z-end, .z-punctuation.z-definition.z-tag.z-begin, .z-punctuation.z-definition.z-tag {
color: #39bae6;
}
.z-entity.z-other.z-attribute-name {
color: #ffb454;
}
.z-variable.z-function, .z-variable.z-annotation {
color: #ffb454;
}
.z-support.z-function, .z-support.z-macro {
color: #fe7d83;
}
.z-support.z-constant {
color: #f29668;
font-style: italic;
}
.z-support.z-type, .z-support.z-class {
color: #39bae6;
font-style: italic;
}
.z-invalid {
color: #ff7c6d;
}
.z-invalid.z-deprecated {
color: #ffffff;
background-color: #00bbff;
}
.z-meta.z-diff, .z-meta.z-diff.z-header {
color: #c594c5;
}
.z-source.z-ruby .z-variable.z-other.z-readwrite {
color: #ffb454;
}
.z-source.z-css .z-entity.z-name.z-tag, .z-source.z-sass .z-entity.z-name.z-tag, .z-source.z-scss .z-entity.z-name.z-tag, .z-source.z-less .z-entity.z-name.z-tag, .z-source.z-stylus .z-entity.z-name.z-tag {
color: #59c2ff;
}
.z-source.z-css .z-support.z-type, .z-source.z-sass .z-support.z-type, .z-source.z-scss .z-support.z-type, .z-source.z-less .z-support.z-type, .z-source.z-stylus .z-support.z-type {
color: #798491;
}
.z-support.z-type.z-property-name {
color: #39bae6;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #798491;
}
.z-constant.z-numeric.z-line-number.z-match {
color: #00bbff;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #c2d94c;
}
.z-message.z-error {
color: #ff7c6d;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-source.z-json .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #39bae6;
}
.z-markup.z-heading {
color: #00bbff;
font-weight: bold;
}
.z-string.z-other.z-link, .z-markup.z-underline.z-link {
color: #95e6cb;
text-decoration: underline;
font-style: italic;
}
.z-punctuation.z-definition.z-image {
color: #ffb454;
}
.z-markup.z-italic {
color: #fe7d83;
font-style: italic;
}
.z-markup.z-bold {
color: #fe7d83;
font-weight: bold;
}
.z-markup.z-italic .z-markup.z-bold, .z-markup.z-bold .z-markup.z-italic {
font-weight: bold;
font-style: italic;
}
.z-markup.z-raw {
background-color: #bfbab0;
}
.z-markup.z-raw.z-inline {
background-color: #bfbab0;
}
.z-meta.z-separator {
color: #798491;
background-color: #bfbab0;
font-weight: bold;
}
.z-markup.z-quote {
color: #f29718;
font-style: italic;
}
.z-markup.z-list.z-numbered.z-bullet, .z-markup.z-list .z-punctuation.z-definition.z-list_item {
color: #95e6cb;
}
.z-markup.z-inserted {
color: #c2d94c;
}
.z-markup.z-changed {
color: #39bae6;
}
.z-markup.z-deleted {
color: #fe7d83;
}
.z-markup.z-strike {
color: #e6b673;
}
.z-markup.z-table {
color: #39bae6;
background-color: #bfbab0;
}
.z-text.z-html.z-markdown .z-markup.z-raw.z-inline {
color: #f29668;
}
.z-text.z-html.z-markdown .z-meta.z-dummy.z-line-break {
color: #798491;
}
.z-markup.z-raw.z-block.z-fenced.z-markdown {
color: #bfbab0;
background-color: #bfbab0;
}
.z-punctuation.z-definition.z-fenced.z-markdown, .z-variable.z-language.z-fenced.z-markdown {
color: #798491;
background-color: #bfbab0;
}
.z-variable.z-language.z-fenced.z-markdown {
color: #798491;
}
.z-markup.z-inserted.z-git_gutter {
color: #c2d94c;
}
.z-markup.z-changed.z-git_gutter {
color: #39bae6;
}
.z-markup.z-deleted.z-git_gutter {
color: #ff7c6d;
}
.z-markup.z-ignored.z-git_gutter {
color: #20272c;
}
.z-markup.z-untracked.z-git_gutter {
color: #20272c;
}
.z-gutter_color {
color: #ffffff;
}
.z-acejump.z-label.z-blue {
color: #ffffff;
background-color: #39bae6;
}
.z-acejump.z-label.z-green {
color: #ffffff;
background-color: #c2d94c;
}
.z-acejump.z-label.z-orange {
color: #ffffff;
background-color: #00bbff;
}
.z-acejump.z-label.z-purple {
color: #ffffff;
background-color: #fe7d83;
}
.z-sublimelinter.z-mark.z-warning {
color: #39bae6;
}
.z-sublimelinter.z-gutter-mark {
color: #ffffff;
}
.z-sublimelinter.z-mark.z-error {
color: #ff7c6d;
}
}
@mixin light {
.z-code {
color: #50565a;
background-color: #fafafa;
}
.z-comment, .z-punctuation.z-definition.z-comment {
color: #676c72;
font-style: italic;
}
.z-variable {
color: #50565a;
}
.z-string, .z-constant.z-other.z-symbol {
color: #497700;
}
.z-constant.z-numeric {
color: #b04e00;
}
.z-string.z-regexp, .z-constant.z-character.z-escape {
color: #007b59;
}
.z-constant.z-language {
color: #b04e00;
}
.z-constant.z-character, .z-constant.z-other {
color: #b04e00;
}
.z-variable.z-member {
color: #c33947;
}
.z-keyword, .z-keyword.z-operator.z-word {
color: #0062e8;
}
.z-keyword.z-operator {
color: #a4552c;
}
.z-punctuation.z-separator, .z-punctuation.z-terminator {
color: #50565a;
}
.z-punctuation.z-section {
color: #50565a;
}
.z-punctuation.z-accessor {
color: #a4552c;
}
.z-punctuation.z-definition.z-annotation {
color: #50565a;
}
.z-variable.z-other.z-dollar.z-only.z-js, .z-variable.z-other.z-object.z-dollar.z-only.z-js, .z-variable.z-type.z-dollar.z-only.z-js, .z-support.z-class.z-dollar.z-only.z-js {
color: #8b6426;
}
.z-storage {
color: #0062e8;
}
.z-storage.z-type {
color: #0062e8;
}
.z-entity.z-name.z-function {
color: #a45600;
}
.z-entity.z-name, .z-entity.z-name.z-tag, .z-entity.z-name.z-label {
color: #0070b3;
}
.z-entity.z-other.z-inherited-class {
color: #0070b3;
text-decoration: underline;
}
.z-variable.z-parameter {
color: #b04e00;
}
.z-variable.z-language {
color: #007492;
font-style: italic;
}
.z-entity.z-name.z-tag, .z-meta.z-tag.z-sgml {
color: #007492;
}
.z-punctuation.z-definition.z-tag.z-end, .z-punctuation.z-definition.z-tag.z-begin, .z-punctuation.z-definition.z-tag {
color: #007492;
}
.z-entity.z-other.z-attribute-name {
color: #a45600;
}
.z-variable.z-function, .z-variable.z-annotation {
color: #a45600;
}
.z-support.z-function, .z-support.z-macro {
color: #b94046;
}
.z-support.z-constant {
color: #a4552c;
font-style: italic;
}
.z-support.z-type, .z-support.z-class {
color: #007492;
font-style: italic;
}
.z-invalid {
color: #da0001;
}
.z-invalid.z-deprecated {
color: #ffffff;
background-color: #0062e8;
}
.z-source.z-ruby .z-variable.z-other.z-readwrite {
color: #a45600;
}
.z-source.z-css .z-entity.z-name.z-tag, .z-source.z-sass .z-entity.z-name.z-tag, .z-source.z-scss .z-entity.z-name.z-tag, .z-source.z-less .z-entity.z-name.z-tag, .z-source.z-stylus .z-entity.z-name.z-tag {
color: #0070b3;
}
.z-source.z-css .z-support.z-type, .z-source.z-sass .z-support.z-type, .z-source.z-scss .z-support.z-type, .z-source.z-less .z-support.z-type, .z-source.z-stylus .z-support.z-type {
color: #676c72;
}
.z-support.z-type.z-property-name {
color: #007492;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #676c72;
}
.z-constant.z-numeric.z-line-number.z-match {
color: #0062e8;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #497700;
}
.z-message.z-error {
color: #da0001;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-source.z-json .z-meta.z-structure.z-dictionary.z-json .z-string.z-quoted.z-double.z-json, .z-source.z-json .z-meta.z-structure.z-dictionary.z-json .z-punctuation.z-definition.z-string {
color: #007492;
}
.z-markup.z-heading {
color: #0062e8;
font-weight: bold;
}
.z-string.z-other.z-link, .z-markup.z-underline.z-link {
color: #007b59;
text-decoration: underline;
font-style: italic;
}
.z-punctuation.z-definition.z-image {
color: #a45600;
}
.z-markup.z-italic {
color: #b94046;
font-style: italic;
}
.z-markup.z-bold {
color: #b94046;
font-weight: bold;
}
.z-markup.z-italic .z-markup.z-bold, .z-markup.z-bold .z-markup.z-italic {
font-weight: bold;
font-style: italic;
}
.z-markup.z-raw {
background-color: #50565a;
}
.z-markup.z-raw.z-inline {
background-color: #50565a;
}
.z-meta.z-separator {
color: #676c72;
background-color: #50565a;
font-weight: bold;
}
.z-markup.z-quote {
color: #b04e00;
font-style: italic;
}
.z-markup.z-list.z-numbered.z-bullet, .z-markup.z-list .z-punctuation.z-definition.z-list_item {
color: #007b59;
}
.z-markup.z-inserted {
color: #497700;
}
.z-markup.z-changed {
color: #007492;
}
.z-markup.z-deleted {
color: #b94046;
}
.z-markup.z-strike {
color: #8b6426;
}
.z-markup.z-table {
color: #007492;
background-color: #50565a;
}
.z-text.z-html.z-markdown .z-markup.z-raw.z-inline {
color: #a4552c;
}
.z-text.z-html.z-markdown .z-meta.z-dummy.z-line-break {
color: #676c72;
}
.z-markup.z-raw.z-block.z-fenced.z-markdown {
color: #50565a;
background-color: #50565a;
}
.z-punctuation.z-definition.z-fenced.z-markdown, .z-variable.z-language.z-fenced.z-markdown {
color: #676c72;
background-color: #50565a;
}
.z-variable.z-language.z-fenced.z-markdown {
color: #676c72;
}
.z-markup.z-inserted.z-git_gutter {
color: #497700;
}
.z-markup.z-changed.z-git_gutter {
color: #007492;
}
.z-markup.z-deleted.z-git_gutter {
color: #da0001;
}
.z-markup.z-ignored.z-git_gutter {
color: #696b6c;
}
.z-markup.z-untracked.z-git_gutter {
color: #696b6c;
}
.z-gutter_color {
color: #ffffff;
}
.z-acejump.z-label.z-blue {
color: #ffffff;
background-color: #007492;
}
.z-acejump.z-label.z-green {
color: #ffffff;
background-color: #497700;
}
.z-acejump.z-label.z-orange {
color: #ffffff;
background-color: #0062e8;
}
.z-acejump.z-label.z-purple {
color: #ffffff;
background-color: #b94046;
}
.z-sublimelinter.z-mark.z-warning {
color: #007492;
}
.z-sublimelinter.z-gutter-mark {
color: #ffffff;
}
.z-sublimelinter.z-mark.z-error {
color: #da0001;
}
}

13
sass/_variables.scss Normal file
View file

@ -0,0 +1,13 @@
@mixin min-screen($min-width: $body-width) {
@media screen and (min-width: $min-width) {
@content;
}
}
@mixin max-screen($max-width: $body-width) {
@media screen and (max-width: $max-width) {
@content;
}
}
$sidebar-width: 300px;

12
sass/book.scss Normal file
View file

@ -0,0 +1,12 @@
@charset "utf-8";
@use "normalize";
@use "variables";
@use "document";
@use "navigation";
@use "content";
@use "header";
@use "syntax" as syntax;
@include syntax.light;

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

223
static/book.js Normal file
View file

@ -0,0 +1,223 @@
function initToggleMenu() {
var $menu = document.querySelector(".menu");
var $menuIcon = document.querySelector(".menu-icon");
var $page = document.querySelector(".page");
$menuIcon.addEventListener("click", function() {
$menu.classList.toggle("menu-hidden");
$page.classList.toggle("page-without-menu");
});
}
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
};
}
// Taken from mdbook
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <b>.
function makeTeaser(body, terms) {
var TERM_WEIGHT = 40;
var NORMAL_WORD_WEIGHT = 2;
var FIRST_WORD_WEIGHT = 8;
var TEASER_MAX_WORDS = 30;
var stemmedTerms = terms.map(function (w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var termFound = false;
var index = 0;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split(". ");
for (var i in sentences) {
var words = sentences[i].split(" ");
var value = FIRST_WORD_WEIGHT;
for (var j in words) {
var word = words[j];
if (word.length > 0) {
for (var k in stemmedTerms) {
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
value = TERM_WEIGHT;
termFound = true;
}
}
weighted.push([word, value, index]);
value = NORMAL_WORD_WEIGHT;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
var windowWeights = [];
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
// We add a window with all the weights first
var curSum = 0;
for (var i = 0; i < windowSize; i++) {
curSum += weighted[i][1];
}
windowWeights.push(curSum);
for (var i = 0; i < weighted.length - windowSize; i++) {
curSum -= weighted[i][1];
curSum += weighted[i + windowSize][1];
windowWeights.push(curSum);
}
// If we didn't find the term, just pick the first window
var maxSumIndex = 0;
if (termFound) {
var maxFound = 0;
// backwards
for (var i = windowWeights.length - 1; i >= 0; i--) {
if (windowWeights[i] > maxFound) {
maxFound = windowWeights[i];
maxSumIndex = i;
}
}
}
var teaser = [];
var startIndex = weighted[maxSumIndex][2];
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
var word = weighted[i];
if (startIndex < word[2]) {
// missing text from index to start of `word`
teaser.push(body.substring(startIndex, word[2]));
startIndex = word[2];
}
// add <em/> around search terms
if (word[1] === TERM_WEIGHT) {
teaser.push("<b>");
}
startIndex = word[2] + word[0].length;
teaser.push(body.substring(word[2], startIndex));
if (word[1] === TERM_WEIGHT) {
teaser.push("</b>");
}
}
teaser.push("…");
return teaser.join("");
}
function formatSearchResultItem(item, terms) {
var li = document.createElement("li");
li.classList.add("search-results__item");
li.innerHTML = `<a href="${item.ref}">${item.doc.title}</a>`;
li.innerHTML += `<div class="search-results__teaser">${makeTeaser(item.doc.body, terms)}</div>`;
return li;
}
// Go from the book view to the search view
function toggleSearchMode() {
var $bookContent = document.querySelector(".book-content");
var $searchContainer = document.querySelector(".search-container");
if ($searchContainer.classList.contains("search-container--is-visible")) {
$searchContainer.classList.remove("search-container--is-visible");
document.body.classList.remove("search-mode");
$bookContent.style.display = "block";
} else {
$searchContainer.classList.add("search-container--is-visible");
document.body.classList.add("search-mode");
$bookContent.style.display = "none";
document.getElementById("search").focus();
}
}
function initSearch() {
var $searchInput = document.getElementById("search");
if (!$searchInput) {
return;
}
var $searchIcon = document.querySelector(".search-icon");
$searchIcon.addEventListener("click", toggleSearchMode);
var $searchResults = document.querySelector(".search-results");
var $searchResultsHeader = document.querySelector(".search-results__header");
var $searchResultsItems = document.querySelector(".search-results__items");
var MAX_ITEMS = 10;
var options = {
bool: "AND",
fields: {
title: {boost: 2},
body: {boost: 1},
}
};
var currentTerm = "";
var index = elasticlunr.Index.load(window.searchIndex);
$searchInput.addEventListener("keyup", debounce(function() {
var term = $searchInput.value.trim();
if (term === currentTerm || !index) {
return;
}
$searchResults.style.display = term === "" ? "none" : "block";
$searchResultsItems.innerHTML = "";
if (term === "") {
return;
}
var results = index.search(term, options).filter(function (r) {
return r.doc.body !== "";
});
if (results.length === 0) {
$searchResultsHeader.innerText = `No search results for '${term}'.`;
return;
}
currentTerm = term;
$searchResultsHeader.innerText = `${results.length} search results for '${term}':`;
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
if (!results[i].doc.body) {
continue;
}
// var item = document.createElement("li");
// item.innerHTML = formatSearchResultItem(results[i], term.split(" "));
console.log(results[i]);
$searchResultsItems.appendChild(formatSearchResultItem(results[i], term.split(" ")));
}
}, 150));
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
initToggleMenu();
} else {
document.addEventListener("DOMContentLoaded", function () {
initToggleMenu();
initSearch();
});
}

130
templates/index.html Normal file
View file

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<!-- Enable responsiveness on mobile devices-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% if page %}
{% if page.description %}
<meta name="description" content="{{ page.description }}" />
{% elif config.description %}
<meta name="description" content="{{ config.description }}" />
{% endif %}
{% elif config.description %}
<meta name="description" content="{{ config.description }}" />
{% endif %}
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
{% block js %}
{% endblock js %}
<!-- CSS -->
{% block css %}
<link rel="stylesheet" href="{{ get_url(path="book.css") | safe }}">
{% endblock css %}
{% block extra_head %}
{% endblock extra_head %}
<script>
window.MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']]
},
svg: {
fontCache: 'global'
}
};
</script>
<script async src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
</head>
<body>
<div class="menu">
{% block before_menu %}
{% endblock before_menu %}
<nav role="navigation">
<ul>
{% block menu %}
{% set index = get_section(path="_index.md") %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
<li {% if current_path == subsection.path %}class="active"{% endif %}>
{% set chapter_num = loop.index %}
<a href="{{ subsection.permalink | safe }}">
{% if config.extra.book_number_chapters %}<strong>{{ chapter_num }}.</strong>{% endif %}
{{ subsection.title }}
</a>
{% if subsection.pages %}
<ul>
{% for page in subsection.pages %}
<li {% if current_path == page.path %}class="active"{% endif %}>
<a href="{{ page.permalink | safe }}">
{% if config.extra.book_number_chapters %}<strong>{{ chapter_num }}.{{ loop.index }}.</strong>{% endif %}
{{ page.title }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
{% endblock menu %}
</ul>
</nav>
{% block after_menu %}
{% endblock after_menu %}
</div>
<div class="page">
<div class="page__header">
<div class="menu-icon">
<span></span>
<span></span>
<span></span>
</div>
{% if config.build_search_index %}
<span class="search-icon">🔎</span>
{% endif %}
</div>
<div class="page__content">
{% if config.build_search_index %}
<div class="search-container">
<input id="search" type="search" placeholder="Search..">
<div class="search-results">
<div class="search-results__header"></div>
<ul class="search-results__items"></ul>
</div>
</div>
{% endif %}
<div class="book-content">
{% block content %}
{% endblock content %}
</div>
</div>
<div class="prev-link">
{% block prev_link %}
{% endblock prev_link %}
</div>
<div class="next-link">
{% block next_link %}
{% endblock next_link %}
</div>
</div>
{% block js_body %}
{% if config.build_search_index %}
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") | safe }}"></script>
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") | safe }}"></script>
{% endif %}
<script type="text/javascript" src="{{ get_url(path="book.js") | safe }}"></script>
{% endblock js_body %}
</body>
</html>

40
templates/page.html Normal file
View file

@ -0,0 +1,40 @@
{% extends "index.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
{{ page.content | safe }}
{% endblock content %}
{% block prev_link %}
{% if page.smaller %}
<a class="previous" href="{{ page.smaller.permalink | safe }}"><</a>
{% else %}
{# No page before, find the link for the section it's in if there is one #}
{% set parent = get_section(path=page.ancestors | reverse | first) %}
<a class="previous" href="{{ parent.permalink | safe }}"><</a>
{% endif %}
{% endblock prev_link %}
{% block next_link %}
{% if page.higher %}
<a class="next" href="{{ page.higher.permalink | safe }}">></a>
{% else %}
{# No page after, find the link for the following section #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
{% if found_current %}
<a class="next" href="{{ subsection.permalink | safe }}">></a>
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% for p in subsection.pages %}
{% if p.permalink == page.permalink %}
{% set_global found_current = true %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% endblock next_link %}

52
templates/section.html Normal file
View file

@ -0,0 +1,52 @@
{% extends "index.html" %}
{% block content %}
<h1>{{ section.title }}</h1>
{{ section.content | safe }}
{% endblock content %}
{% block prev_link %}
{# need to find the last page of the previous section or the previous section directly
if there isn't any pages in it #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections | reverse %}
{% set subsection = get_section(path=s) %}
{% if subsection.permalink == section.permalink %}
{% set_global found_current = true %}
{% else %}
{% if found_current %}
{% if subsection.pages %}
{% set last_page = subsection.pages | last %}
<a class="previous" href="{{ last_page.permalink | safe }}"><</a>
{% else %}
<a class="previous" href="{{ subsection.permalink | safe }}"><</a>
{% endif %}
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% endif %}
{% endfor %}
{% endblock prev_link %}
{% block next_link %}
{% if section.pages %}
{% set next_page = section.pages | first %}
<a class="next" href="{{ next_page.permalink | safe }}">></a>
{% else %}
{# No page in the section, find the link for the following section #}
{% set index = get_section(path="_index.md") %}
{% set found_current = false %}
{% for s in index.subsections %}
{% set subsection = get_section(path=s) %}
{% if found_current %}
<a class="next" href="{{ subsection.permalink | safe }}">></a>
{# no break #}
{% set_global found_current = false %}
{% endif %}
{% if subsection.permalink == section.permalink %}
{% set_global found_current = true %}
{% endif %}
{% endfor %}
{% endif %}
{% endblock next_link %}

13
theme.toml Normal file
View file

@ -0,0 +1,13 @@
name = "book"
description = "A book theme inspired from GitBook/mdBook"
license = "MIT"
homepage = "https://github.com/getzola/book"
min_version = "0.17.0"
demo = "https://getzola.github.io/book/"
[extra]
book_number_chapters = true
[author]
name = "Vincent Prouillet"
homepage = "https://www.vincentprouillet.com"