Introducing Inlyne, a GPU powered yet browsless tool to help you quickly view markdown files in the blink of an eye.

Related tags

Command-line inlyne
Overview

Inlyne - a GPU powered, browserless, markdown + html viewer

inlyne README.md --theme dark/light

About

Markdown files are a wonderful tool to get formatted, visually appealing, information to people in a minimal way. Except 9 times out of 10 you need an entire web browser to quickly open a file...

Introducing Inlyne, a GPU powered yet browsless tool to help you quickly view markdown files in the blink of an eye.

Install

To install just use cargo install inlyne, everything comes pre-bundled.

Features

Over time the features of this application will continue to grow. However there are a few core features that will remain at the heart of the project.

  • Browserless - People shouldn't need electron or chrome to quickly view markdown files in a repository.
  • GPU Powered - Thanks to the WGPU Project rendering can and will be done as much on the GPU as we can get away with.
  • Basic HTML Rendering - HTML is used in almost all project markdown files, thus having the bare minimum html to support common use cases is necessary, but don't expect forms and buttons.
  • Live Code Change - Inlyne will monitor your markdown file for any write modifications and automatically refresh the document where you left off. It's designed to work seamlessly and allow you to make edits on the fly.

What does it support?

Tables

Super cool tables For organising data
Favourite band Nickleback

Sizable images

Code Blocks (with syntect highlighting)

// Code thats drawing this text
let bounds = (screen_size.0 - pos.0 - DEFAULT_MARGIN, screen_size.1);
self.glyph_brush.queue(&text_box.glyph_section(*pos, bounds));

Lists and Links

  1. Inlyne
  2. WGPU Project
  3. Lyon Project
  4. Winit Project

Tasklists

  • Watch Game of Thrones
  • Feed the cat

Hideable sections

Click me to show text

You weren't suppost to see this!

Alignment

Text/Image..

alignment..

:)

Quote Blocks

“Optimism is an occupational hazard of programming: feedback is the treatment. “ Kent Beck

Text Effects

Are these text effects to too much? Theres no such thing

Configuration

Use inlyne --help to see all the command line options. Some of which can be set permentantly by placing an inlyne.toml file into the default dirs configuration folder for your respective OS. Checkout inlyne.toml.sample for an example configuration.

FAQ

Is this a html markdown or html renderer?

All markdown files are converted to html thanks to comrak and rendered from there. So technically its a markdown converter and html renderer.

However for obvious complexity reasons, inlynes only going to support enough html to get by rendering 95% of markdown files such as <br>, <h1>, <img>.. etc.

Unforuntately things like <form> and every single css style isn't going to be in scope

Why not use a browser or Visual Studio Code?

You definitely can! And it'll probably do a lot more accurate job at rendering it.

However wouldn't it be nice to have an application that can quickly open that one file in your vim setup? I'd like to think of this as the macOS preview or Adobe Acrobat of markdown.

Contributing

Send your PRs! Send your issues! Everything will help :)

License

Any code that you can in this repository, you can copy under the MIT license.

MIT License

Comments
  • Give me window resizes or give me death

    Give me window resizes or give me death

    Resolves #25

    The comment linked below covers things pretty well. The gist is that we can lazily handle window resizing since we will get a RedrawRequested afterwards. This prevents a bunch of WindowResizeds from clogging up the event queue

    https://github.com/trimental/inlyne/compare/main...LovecraftianHorror:give-me-window-resizes-or-give-me-death?expand=1#diff-42cb6807ad74b3e201c5a7ca98b911c5fa08380e942be6e4ac5807f8377f87fcR191-R216

    opened by LovecraftianHorror 12
  • A more friendly configuration file

    A more friendly configuration file

    I'm not a programmer and I tried to configure inlyne, but after half an hour I still can't get "inlyne.toml" to work. dirs seems to be a library? I really don't know how to use it. Why not read "inlyne.toml" from the same directory as inlyne.exe? This is portable and very easy to use. Why don't we use it this way?

    Or the command line argument, "-conf inlyne.toml"

    opened by Frozen1084 10
  • Initial codeblock syntax highlighting support

    Initial codeblock syntax highlighting support

    Resolves #8

    The comrak feature tweaking is to get rid of the default clap feature which is only useful for the comrak binary

    This implements the initial support for syntax highlighting code blocks, but it seems there are some bugs in how some spans with just whitespace are handled (e.g. the lines starting with async and return) which I would appreciate some help troubleshooting since the TokenPrinter is a big ball of mutable state that is pretty hard to follow.

    Here is some of the syntax highlighted code where the indentation is having some obvious issues. The indentation issues are reproducible when just having comrak include colored spans in codeblocks without any of the code for respecting the span's color

    Before

    image

    After

    image


    Also worth noting that the HTML portion of the code snippet should also be indented, but isn't in either this PR or main

    // requires Bun v0.1.0 or later
    // react-ssr.tsx
    import { renderToReadableStream } from "react-dom/server";
    
    const dt = new Intl.DateTimeFormat();
    
    export default {
      port: 3000,
      async fetch(request: Request) {
        return new Response(
          await renderToReadableStream(
            <html>
              <head>
                <title>Hello World</title>
              </head>
              <body>
                <h1>Hello from React!</h1>
                <p>The date is {dt.format(new Date())}</p>
              </body>
            </html>
          )
        );
      },
    };
    
    // bun react-ssr.tsx
    
    opened by LovecraftianHorror 7
  • Bad window resize performance with large READMEs on some systems

    Bad window resize performance with large READMEs on some systems

    For some reason on my system resizing the window has really really bad performance

    Demo

    https://user-images.githubusercontent.com/30302768/185724443-d6ed6c2c-0760-48cf-ad69-a46e35a53f8d.mp4

    As you can see it processes 100+ events for WindowEvent::Resized that all take ~20ms along with one beefy event for Event::RedrawRequested that takes ~16s

    If I do small shifts to the window then it's not a problem. It's only when a lot of WindowEvent::Resized get queued up that Event::RedrawRequested takes a long time

    What's the CPU usage look like?

    It takes up all of one logical core for the whole duration

    Memory usage?

    Peak usage is usually over 10 GiB :smiling_face_with_tear:

    This does not go down after the resize finishes

    What if you do it twice?

    The WindowEvent::Resizeds consistently each takes ~20ms while the Event::RedrawRequested takes around 1.5 seconds

    Is this a recent problem?

    Nope. I can reproduce it on commits back before I even started contributing

    Does this happen with smaller READMEs?

    No! The issue seems to only exist when the README is big enough that another WindowEvent::Resized gets queued up before the last one finishes

    Profiles

    Both profiles are from the same situation shown in the video aka one resize and then killing the program

    CPU usage

    image

    As you can see the vast majority of the time is spent in glyph cache related things

    Memory usage

    image

    Note: 12.3GB peak memory usage

    Unsurprisingly also dominated by glyph cache related things

    Investigation

    The vast majority of the time for the WindowEvent::Resized related calls are taken up from this .glyph_bounds() call

    https://github.com/trimental/inlyne/blob/14422b0d3a2a7893ee483df8b5c6ae9fc239d4e9/src/text.rs#L100

    The vast majority of the time for the Event::RedrawRequested call is taken up by this .draw_queued_with_transform() call

    https://github.com/trimental/inlyne/blob/14422b0d3a2a7893ee483df8b5c6ae9fc239d4e9/src/renderer.rs#L572-L597

    Two things both reduce the time taken for Event::RedrawRequested to ~1.5s and reduced the peak memory usage from ~12GB to ~4.5GB

    1. Adding .draw_cache_position_tolerance(1.0) to the glyph brush builder (This ignores sub-pixel position changes when caching glyphs)
    2. Setting the scale to 1.0 (My hunch here was that the hidpi_scale was inconsistently used somewhere causing duplicate glyphs to be added to the cache)

    And sadly I haven't found anything that makes WindowEvent::Resized process faster. I think filtering consecutive queued WindowEvent::Resized events could help since there is no reason to process a resize if there is another resize already queued after it. I did a hack to only process every 10th WindowEvent::Resized which made things refresh smoothly aside from having obvious graphical issues. Changing the event loop to allow inspecting queued up events would be very non-trivial though. My best idea on how to handle it would be to send events over a channel to another thread that actually processes them, but this involves a lot of changes from lifetimes, callbacks, etc.

    All of these seem like they're trying to work around some underlying issue that I can't find though

    Pending questions

    Does something queue up each time there is a WindowEvent::Resized? It seems that way since the time taken up by Event::RedrawRequested depends on the number of WindowEvent::Resized that have run before it

    What's causing the glyph cache to blow up so much? Even with the hack above 4.5 GB peak memory usage still seems very high

    opened by LovecraftianHorror 6
  • Have line-delta scrolling shift by 30 pixels per line

    Have line-delta scrolling shift by 30 pixels per line

    Partially resolves #3

    This could be improved by calculating a more appropriate value to scroll by line, but this change at least makes things more usable when line-delta scrolling is used

    opened by LovecraftianHorror 6
  • Live reloading (exciting)

    Live reloading (exciting)

    Definitely an exciting PR that adds live reloading by watching the file directory for changes and then sending new string data to the interpreter. Live reloading is one of the things I most wanted for inlyne so I'm glad to at least get a proof of concept PR out.

    There a few graphical glitches I'm experiencing on macOS with partial rendering which could be the same as stated in https://github.com/trimental/inlyne/issues/21. Honestly after looking into it I'm tempted to think it might be a wgpu issue, as it seems it takes two redraws for things drawn previously to show to the screen. Maybe a swap chain issue? I'll have to look into it more.

    @LovecraftianHorror If you have the time to quickly help test this on linux when you get a chance that would be a great help even if it's on the weekend ❤️ (I should hurry up and get my dev setup on asahi linux)

    opened by trimental 5
  • Custom Keybinds

    Custom Keybinds

    I'm planning on adding support for specifying custom keybinds this weekend. This is the general gist of how I want to expose it

    # Custom keybinds for actions
    # Each entry maps an action to a key combo
    # Action -> predefined list of possible interactions to perform
    # Key Combo -> Either a single modified key or an array of modified keys
    # Modified Key -> Either an unmodified key or an obj with a key and modifiers
    # Possible Modifiers: ["Alt", "Ctrl", "Os", "Shift"]
    #     (Note: shift can only be used on keys that don't have a different key for
    #     no-shift and shift like "Enter" or "Space")
    # Possible Actions: [
    #     "ToTop", "ToBottom",
    #     "ScrollUp", "ScrollDown",
    #     "PageUp", "PageDown",
    #     "ZoomIn", "ZoomOut", "ZoomReset",
    #     "Copy",
    #     "Quit",
    # ]
    # Possible Keys: [
    #     ... All the typical letters, numbers, and symbols
    #     "Enter", "Space", "Tab", Backspace", "Esc", PageUp", "PageDown",
    #     "PageLeft", "PageRight", "Home", "End", "Delete", "Insert", "F1"-"F12", etc.
    # ]
    keybinds = [
        ["ToTop", "Home"],
        ["ToBottom", "End"],
        ["Copy", { key = "c", mod = ["Ctrl"] }],
        ["ToTop", ["g", "g"]],
        ["ToBottom", "G"],
        ["Copy", "y"],
    ]
    

    One thing that I noticed that may complicate things is that a surprising number of keys don't get picked up with a VirtualKeyCode on my keyboard like $%^&() etc.

    Another thing is that there may be system differences here too. I noticed that @trimental uses VirtualKeyCode::Equals+Shift to detect a "+", but for me it registers as a VirtualKeyCode::Plus. It's actually impossible for me to use VirtualKeyCode::Equals with shift on my keyboard layout. Switching to using the scancode could fix this and the missing keys issue

    opened by LovecraftianHorror 5
  • Add font configuration

    Add font configuration

    Adds font configuration through the [font-options] section of the configuration file.

    # # Change the appearance of text with font options
    # [font-options]
    # # Name of font for regular text
    # regular-font = "Chalkduster"
    # # Name of font for monospace text such as code
    # monospace-font = "Monaco"
    
    Screenshot 2022-08-17 at 11 45 17 pm

    Failing to find the requested font it gives an error similar to

    Error: No font found for monospace font
    
    Caused by:
        no font found
    

    However in the case no font is provided it falls back to the system default monospace and sans serif font.

    opened by trimental 5
  • Support more language types and error display

    Support more language types and error display

    https://i.imgur.com/3w5h93E.png

    There are two problems with the window in the image. 1, can't display text other than English 2, there is a chance that only part of the content is displayed. Both windows load the same file.

    opened by Blue-Savage 5
  • Consider pushing a tag when doing releases

    Consider pushing a tag when doing releases

    I put together an inlyne AUR package since a browserless markdown viewer is something I've wanted for quite a while!

    It would make the PKGBUILD a lot simpler if some vX.Y.Z or X.Y.Z tag was pushed for each release. At the moment I'm basing releases off the commit hash that bumps the version

    opened by LovecraftianHorror 5
  • Custom keybindings

    Custom keybindings

    Resolves #34

    This implements things as listed in #34 with a couple of small tweaks due to issues in winit

    • The amount of usable keys is slimmed down
    • Shift now has to be specified regardless of the key (I originally wanted "G" to represent Shift+g, but the platform inconsistencies with how things like + are expressed (Shift+= vs Shift++) made me walk this back)

    There is now a new section in the config file for keybindings. Here's the one from `inlyne.toml.sample

    [keybindings]
    # Base will override the defaults if set
    # Default: Not set
    base = [
        ["ToTop", "Home"],
        ["ToBottom", "End"],
        ["Copy", { key = "c", mod = ["Ctrl"] }],
        ["ToTop", ["g", "g"]],
        ["ToBottom", { key = "g", mod = ["Shift"] }],
        ["Copy", "y"],
    ]
    # Extra will be applied on top of base/defaults
    extra = ... # Refer to `base`
    

    A decent amount of the code goes into deserializing this. I wanted to allow for the config to be simple, so you can see that you can do things like provide a single key instead of a full combo, or provide just the key if there are no modifiers

    The other bulk of the changes is for handling KeyCombos. It's a struct that gets initialized with the keybindings. Afterwards it can consume keys and will emit if they corresponded to some action


    Here's everything in action. The section of my config for reference

    [keybindings]
    extra = [
        ["Copy", "y"],
        ["ScrollUp", "k"],
        ["ScrollDown", "j"],
        ["ToTop", ["g", "g"]],
        ["ToBottom", { key = "g", mod = ["Shift"] }],
        ["Quit", "q"],
        ["Quit", [{ key = "z", mod = ["Shift"] }, { key = "z", mod = ["Shift"] }]],
        ["Quit", [{ key = "z", mod = ["Shift"] }, { key = "q", mod = ["Shift"] }]],
    ]
    

    https://user-images.githubusercontent.com/30302768/187098807-18d806e2-fa8c-4afc-9c87-588a196a3c9a.mp4

    opened by LovecraftianHorror 4
  • [Suggestion] Add math support

    [Suggestion] Add math support

    Hello there ;)

    I would like to use Inlyne for viewing my documents which contain (a lot) of mathematical notations and think support for math grammar would be a great addition to inlyne.

    opened by C0ffeeCode 0
  • [Suggestion] History and Navigation

    [Suggestion] History and Navigation

    Hey there!

    Motivation

    After #50 is closed, clicking a link to a local md file will open it in the current window.

    I think it makes sense to add some lightweight "history" and "navigation" in order to be able to go back to the previously opened file.

    Other alternatives

    Well, if every markdown file has a link to the previous one, this is a none issue. Like if you create a strict hierarchy. But it relies on the content of the markdown files, which is outside our control.

    I think it makes sense to add this, especially now (or rather soonish ;)) that the content of the current window is overwritten.

    To decide

    Shortcuts for navigation and maybe even some kind of menu-bar/ui buttons?

    opened by nerdachse 1
  • [Suggestion] Libify inlyne to make it an embeddable markdown viewer

    [Suggestion] Libify inlyne to make it an embeddable markdown viewer

    Hey there!

    Motivation

    Imagine a world where we could embed inlyne into other applications, like e.g. (via a plugin) a bevy-engine game, or any other kind of (wgpu-based) application.

    Necessities

    What's necessary for that? Well, another API that we can hand a markdown file (byte content?) and take the result of the rendering and put it to a texture or something like that.

    Maybe in the future we could even make the first part renderer-agnostic.

    I am not yet deep enough into the codebase to know what exactly is necessary, so it's all a bit fuzzy, but I can't shake the feeling that this is something I really, really want... :)

    opened by nerdachse 1
  • Add support for interactive search

    Add support for interactive search

    Really not sure how complicated this would be, but it would be nice to be able to search through the text in the document

    Mapping these to actions I was thinking something along the lines of

    • SearchStart - Ctrl+f (Cmd+f on Mac I would assume)
    • SearchFinish - Enter (Only registers after we started a search)
    • SearchExit - Escape
    • SearchNextResult - n
    • SearchPreviousResult - N

    UI changes I think MVP at the very least needs to select and focus the current result

    opened by LovecraftianHorror 0
  • Handle streaming decoding of images

    Handle streaming decoding of images

    Currently inlyne will hold the raw image data in memory. This means that physically large (as in just large width and height) images can take up a lot of memory. Here is the peak memory usage when viewing bun's README for reference

    image

    As you can see the majority of the memory usage is from holding image data in memory (77 MB when the peak is 110 MB)

    I think my current preferred approach for dealing with this would be to save the remote images locally (in the user's cache dir), and perform streaming decoding to read the image on demand when it get's rendered. From my bit of testing it looks like image rendering is handled lazily, so it shouldn't involve reading the image over and over again when rendering

    Other approaches could be to hold the remote image in memory and perform streaming decoding when the image gets rendered or to do streaming decoding on the image upfront and store the raw image data in some quick to decompress in-memory blob (like zstd)

    The preferred approach would likely depend on how noticeable the delay is when it comes to reading off disk and decoding


    I'm planning on handling this change (but feel free to work on it if you want)

    This is the last memory-hog aspect of inlyne. The remaining offenders would appear to be from GPU initialization, glyph crunching, converting non RGBA8 images to RGBA8, and converting the markdown to HTML. At first glance a lot of these look like they would be out of our hands, but I'm still planning on digging in more to check anyways.

    opened by LovecraftianHorror 1
Releases(v0.2.1)
Owner
null
GPT-3 powered CLI tool to help you remember bash commands.

Rusty: GPT-3 Powered CLI Tool Convert natural language into executable commands directly from the terminal! Open source CLI tool powered by OpenAI (br

Zahid Khawaja 287 Apr 19, 2023
Scouty is a command-line interface (CLI) to keep an eye on substrate-based chains and hook things up

scouty is a command-line interface (CLI) to keep an eye on substrate-based chains and hook things up

TurboFlakes 15 Aug 6, 2022
An eye that keeps track of your Roblox status and shares it with others

Roblox presence for Discord with only one native standalone executable that relies on zero external dependencies, and doesn't need to be installed.

null 7 Dec 25, 2022
A filesystem driver that allows you to view your Blackboard course contents as if they were normal files and folders on your system!

BlackboardFS Blackboard: noun A website so bad that it might as well be a network drive. BlackboardFS is a filesystem driver that allows you to view y

null 22 Sep 4, 2023
Rust-powered CLI tool designed to simplify and streamline the release process with help of ChatGPT

$ releasecraftsman ????‍♂️?? Automate Your Release Process with Precision and Ease. ?? Features Generate well-crafted release notes using GPT-3.5 and

Tornike Gomareli 7 Sep 21, 2023
This is a tool to evaluate or export code from Markdown files.

Evaluate Markdown This is a tool to evaluate or export code from Markdown files. Why? Because I like writing Markdown files with code snippets (it's g

Balazs Nadasdi 5 Apr 25, 2023
lemmy-help is a emmylua parser as well as a CLI which takes that parsed tree and converts it into vim help docs.

lemmy-help is a emmylua parser as well as a CLI which takes that parsed tree and converts it into vim help docs.

Vikas Raj 117 Jan 3, 2023
Terminal UI for leetcode. Lets you browse questions through different topics. View, solve, run and submit questions from TUI.

Leetcode TUI Use Leetcode in your terminal. Why this TUI: My motivation for creating leetcode-tui stemmed from my preference for tools that are lightw

Akarsh 8 Aug 10, 2023
A tool that allow you to run SQL-like query on local files instead of database files using the GitQL SDK.

FileQL - File Query Language FileQL is a tool that allow you to run SQL-like query on local files instead of database files using the GitQL SDK. Sampl

Amr Hesham 39 Mar 12, 2024
A CLI tool which can help you automatically kill process of your choice. Useful for freeing up memory and CPU usage!

Quickiller There are always programs such as chrome that keep eating up your resources even when closed! The only way to prevent this is to kill all o

Codingsquirrel 1 Dec 8, 2021
Jumpy is a tool that allows to quickly jump to one of the directory you've visited in the past

Jumpy Jumpy is a tool that allows to quickly jump to one of the directory you've visited in the past. It is heavily inspired by Zoxide but is more lig

Clément Nerma 2 Oct 3, 2022
Tool that was built quickly for personal needs, you might find it useful though

COPYCAT Produced with stable-diffusion Clipboard (copy/paste) history buffer for terminal emulators, MAC OS gui and VIM* environment usage. Rrequireme

Dragan Jovanović 4 Dec 9, 2022
STKLR is a tool to help you automatically link up named stuff in your rust docs!

_____ _______ _ ___ _____ / ____|__ __| |/ / | | __ \ | (___ | | | ' /| | | |__) | \___ \ | | | < | | | _ / ___

Jer 3 Oct 25, 2022
A workflow tool for quickly running / testing something you are working on

runfast What is it? This is a program intended to be run in a project directory to set up a project run command, and remember it so we dont have to ty

anna 4 Dec 16, 2022
Sniffer - a tool to quickly inspect csv and flat-file files for basic information

sniffer sniffer is a tool to quickly inspect csv and flat-file files for basic information. Need to see how many rows are in a csv file? Want to see t

Daniel B 10 Apr 4, 2023
tmplt is a command-line interface tool that allows you to quickly and easily set up project templates for various programming languages and frameworks

tmplt A User Friendly CLI Tool For Creating New Projects With Templates About tmplt is a command-line tool that lets users quickly create new projects

Humble Penguin 35 Apr 8, 2023
Scriptable tool to read and write UEFI variables from EFI shell. View, save, edit and restore hidden UEFI (BIOS) Setup settings faster than with the OEM menu forms.

UEFI Variable Tool (UVT) UEFI Variable Tool (UVT) is a command-line application that runs from the UEFI shell. It can be launched in seconds from any

null 4 Dec 11, 2023
mdBook is a utility to create modern online books from Markdown files.

Create book from markdown files. Like Gitbook but implemented in Rust

The Rust Programming Language 11.6k Jan 4, 2023
scan markdown files and execute `console` blocks

exec-commands − scan markdown files and execute console blocks exec-commands is a utility to update command-line-tool examples embedded in markdown fi

Hajime Suzuki 3 Nov 27, 2022