Giter Club home page Giter Club logo

pris's Introduction

Pris

Pris is a domain-specific language for designing slides and other graphics.

Build Status Gitter

Example

The obligatory “hello world”:

{
  put t("Hello world") at (0.1w, 0.5h)
}

And to show a little more of the language, here is a slightly more elaborate program that also draws lines:

top_left = (0w, 0h)
top_right = (1w, 0h)
bottom_left = (0w, 1h)
bottom_right = (1w, 1h)

{
  put line(bottom_right) at top_left
  put line(top_right - bottom_left) at bottom_left

  font_family = "Cantarell"
  font_size = 0.3h
  color = #882244
  put t("A language for designing slides.") at (0.1w, 0.1w + font_size)
}

{
  color = #000000
  put line((1w, 0h)) at (0w, 0.5h)
}

It creates two slides, the first one with a cross in it, the second one with a horizontal line. The first slide contains text in dark purple.

Comparison to other technologies

  • Pris is similar to LaTeX with Beamer in the sense that you write your slides in a text-based, human readable format, from which a pdf is produced. Pris differs from LaTeX with Beamer in not doing any lay-out. All elements must be placed manually.
  • Pris is similar to reveal.js in that its control over visuals superficially resembles css. It differs from reveal.js in requiring a separate compilation step that renders a pdf. It differs from html in being imperative rather than declarative.
  • Pris is similar to TikZ in LaTeX, in the sense that it is a domain-specific language for creating graphics. It is similar in providing complete control over where elements are placed. Pris differs from TikZ in not being embedded in LaTeX. It has a more modern syntax, and it has first class support for computation. For instance, arithmetic with coordinates is supported out of the box, and Pris has proper functions, rather than TeX macros.
  • Pris is similar to Fran, in having first-class, composable graphics (although implementation is a work in progress). Pris differs from Fran in not being embedded in Haskell. Pris differs from Fran in placing emphasis on graphics rather than animation.
  • Pris is similar to Diagrams in being a domain-specific language with first-class composable graphics, giving complete control over layout. Pris differs from Diagrams in not being embedded in Haskell. Pris differs from Diagrams in its styling system. Customization in Pris resembles CSS due to dynamic scoping, whereas in Diagrams functions pass around a style value.
  • Pris is vaguely similar to Powerpoint and graphical editors like Illustrator or Inkscape in providing complete control over where elements are placed. It differs in being a text-based format intended to be edited with a text editor, rather than with a graphical editor.
  • Pris is similar to an html canvas element, or to drawing with Skia or Cairo, in providing complete control over how graphics are drawn. It differs from direct canvas drawing in being more high-level (graphic elements can be manipulated as first-class values), and in being a domain-specific language rather than being controlled by a general-purpose scripting language.

Documentation

Building

Pris uses Cairo for drawing and Harfbuzz for text shaping, and links against libcairo.so and libharfbuzz.so. It uses Rsvg to render svg images, for which it links against librsvg-2.so. Ensure that these are installed:

# On Ubuntu
apt install fonts-cantarell libcairo2-dev libharfbuzz-dev librsvg2-dev

# On Arch
pacman -S --needed cantarell-fonts cairo harfbuzz librsvg fontconfig freetype2

Pris is written in Rust and builds with Cargo, the build tool bundled with Rust.

cargo build --release
target/release/pris examples/lines.pris
evince examples/lines.pdf

License

Pris is free software. It is licensed under the GNU General Public License, version 3.

pris's People

Contributors

ruuda avatar tvincent2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pris's Issues

Add support for raster images

Pris currently supports svg images through Rsvg. It should also support loading raster images. For now png-only (likely through libpng, because Pris depends on it already through Cairo anyway) is fine. Jpeg support would be a nice to have. Supporting other image types is a non-goal; it adds extra complexity but brings little value, as it is easy to convert to a supported format via an external program.

The approach would be something like this:

  • Add an element in src/element.rs, analogous to the Svg element.
  • Update the driver in src/driver.rs to render these elements. This might require adding more Cairo bindings.
  • Update the image builtin in src/builtins.rs to detect the image type from the extension, and to produce a correct Element for the returned frame.

Add support for raw, multiline string literals

For easy embedding of code snippets or paragraphs of text, multiline raw string literals can be useful. The current string literals are already multiline, but they don’t strip indentation, which makes them ugly. Also, because they are delimited by ", the " and \ must be escaped, which can be a pain for code snippets that contain strings.

Solution: add a multiline raw string literal, delimited by ---. The opening and closing --- should be on their own line. All whitespace that precedes the closing --- will be stripped from every line. The first and last newline within --- are also stripped. Example:

{
  snippet =
  ---
  fn foo() {
      println!("bar")
  }
  ---
}

would be equivalent to

{
  snippet = "fn foo() {\n    println!(\"bar\")\n}"
}

Please document how to use lists

Hi!

The current example about lists describes how to declare lists, but not how they can be used. Please show we can use them.

Thanks!
Thomas

Expose access to bounding box edges

Currently it is impossible to write a correct center function in Pris. The following has the wrong offset when the top-left corner of the bounding box does not coincide with the origin of a frame:

center = function(frame)
{
  at frame.size * -0.5 put frame
}

The correct version would be:

center = function(frame)
{
  at (frame.size * -0.5) - frame.top_left put frame
}

where top_left is the offset of the top-left corner of the bounding box, to the origin. As the origin is always included in the bounding box (should it be?), this offset is either negative or zero.

Bikeshed: what is a good intuitive name for this? top_left? offset? The following fields also exist currently:

  • width: width of the bounding box.
  • height: height of the bounding box.
  • size: (width, height) of the bounding box.
  • anchor: offset relative to the origin of the frame, where new frames can be adjoined. (Not yet implemented.)

Write a custom lexer

A custom lexer is required to lex single-line comments that run to the end of the line; the lexer generated by Lalrpop cannot currently express this.

Bikeshed: what should the syntax for comments be? # or //? I am leaning towards //, because # is already used for colors.

Syntax highlighting

It would be nice to have syntax highlighting for Pris source files.

Syntax details

A good starting point is the Bison grammar in etc/pris.y. The Pris parser uses a different implementation (in src/lexer.rs and src/parser.rs), but the two should be in sync. The Bison file is used to check that the grammar remains sensible. The tokens defined at the top, together with the string literals (for keywords and suffixes) are all the tokens, and those should be sufficient for syntax highlighting.

Formats

  • Vim
  • Kate
  • Emacs
  • TextMate
  • Sublime Text (covered by TextMate?)
  • GitHub Linguist (covered by TextMate?)
  • Atom (similar to TextMate?)
  • VS Code (preliminary version in etc/vscode)
  • Pygments

I will take care of Vim and Kate myself when I find the time. (Vim is my editor of choice, and Pandoc — which powers my blog — uses highlighting-kate.)

Support drawing svg subsets

From Reddit: it would be nice to add the ability to render subsets of an svg file.

Rsvg does support this with rsvg_render_handle_cairo_sub and rsvg_handle_has_sub, it would not be very difficult to expose this.

What would be required to implement this:

  • Add the ffi wrappers for rsvg_render_handle_cairo_sub and rsvg_handle_has_sub in src/rsvg.rs.
  • Change elements::Element::Svg to include an optional svg element id, and maybe define a wrapper struct so it can be named.
  • Add a variant of builtins::image that supports subset selection, perhaps image_subset(fname: string, element_id: string).
  • Expose the new function in runtime::Env::new. (Handling of builtins needs some refactoring, but for now that is where builtins are exposed.)

Operators should associate left, not right

The expression x - y + z should be parsed as (x - y) + z, not x - (y + z).

The reason is is currently parsed as the latter, is due to the right-recursion in the parser. This can be avoided by not using recursion to handle the right-hand side, but parsing in a loop instead. Instead of recursing, we do another iteration of the loop. The value parsed so far can be accumulated as a single expression.

Allow custom dimensions

Hello,

If I understand correctly, the dimensions of the generated pdf files are currently hard-coded to 1920×1080 (e.g. in pris.rs).
It would be nice to allow the user to set custom dimensions, for instance using command line parameters or, even better, in .pris files themselves.

Thanks a lot for making pris!
Thomas

Rotate and bounding boxes

I want to add a rotate function, but bounding boxes are tricky. We can rotate the bounding box, and compute the new bounding box that fits it, but that means that rotating by pi/4 twice is not the same as rotating by pi/2 once, which would be a shame.

An alternative would be to never flatten bounding boxes, but to compute them on the fly. This would work for rotating compound frames, and it would solve the twice pi/4 vs once pi/2 problem. A tricky thing is computing bounding boxes for shapes made of Bézier curves. It’s doable though, and we don't have curves yet anyway, but I do intend to support them. For polygons it’s not too hard.

Unable to build on 32 bit platforms

At the moment pris fails to build on 32 bit platforms. The problem seems to be in src/cairo.rs, line 231:

Glyph::new(self.0.index, self.0.x + dx, self.0.y + dy)

Glyph::new takes a u64 as the first parameter, but self.0.index is a c_ulong, which is a u32 on 32 bit platforms and thus cannot be implicitly converted into a u64. The solution is to explicitly cast it, which should work on both 32 and 64 platforms:

Glyph::new(self.0.index as u64, self.0.x + dx, self.0.y + dy)

Add element as text backend

Pris internally produces frames that contain elements. Elements are then rendered to pdf by the driver. There should be an additional driver that outputs a serialized representation of every element. It could be json, for example, but any text-based format would be fine.

Such an output format would be useful for creating golden tests. If an internal change should not affect the output, then the pdf, as well as the serialized elements should remain unchanged. But if there is a change after all, it is hard to tell from the pdf file what that change is exactly. Diffing the serialized format should be much easier. Furthermore, the exact output pdf depends on the Cairo version used, which makes it not portable across systems. In particular, I cannot create golden pdfs on my machine and expect them to match on CI. But a serialized output format would be portable, and suitable for use in golden tests.

Windows support

Pris currently builds on Linux out of the box, and on OS X by installing a few dependencies with brew. On Windows however, the situation is more difficult. I did manage to produce a working binary under MSYS2, but I don’t have a clear deterministic guide for getting this to work.

Once it works, the steps should be automated in order to run CI on AppVeyor.

In an MSYS2 shell, I installed the following packages:

make
gcc
pkg-config
mingw-w64-x86_64-cairo
mingw-w64-x86_64-harfbuzz
mingw-w64-x86_64-fontconfig
mingw-w64-x86_64-freetype
mingw-w64-x86_64-librsvg

With a bit of trial and error, and by manually including the linker flags reported by pkg-config in my RUSTFLAGS (including the double ones), I was able to produce a working binary. The binary then depends transitively on 24 (if I counted correctly) dlls. I would be good to identify those in order to facilitate packaging. On Linux this is not so much of an issue because they are generally installed already, and they can be installed by the system package manager otherwise. It might also be worth investigating static linking of all nonstandard dependencies too.

Highlight on multiline string syntax error is wrong

Consider the following invalid input:

{
  ---
  foo
  ---
}

It triggers the following error message:

Parse error at line 2:

  ---
  ^~~~~~~~~~~~~~~
Error: Parse error in statement: expected import, return, assignment, block, or put.

The highlight of ~~~ should not extend that long; the end of line inside the multiline string should be taken into account.

Accessing glyphs by glyph index or name

Let's say I wanted to add pris as a target for ReX. The issue is that mapping Code points -> Glyph Indices is not one-to-one. For instance, there are 5 glyphs associated to the code point 0x28, a left parenthesis, in STIX, corresponding to 5 different heights.

ReX gets away with this for SVG targets modifying the opentype files, and using private use code points for the unmapped glyphs at the moment, but I'm thinking about moving away from this.

Do you have any thoughts on this? I believe, I would essentially need a way to construct
a cario_glyph_t and I would need to bypass Harfbuzz all together.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.