ā†‘

This is a demonstration of the demonic project, specifically by running editable code snippets from a markdown-converted document.

demonic was inspired by mdbook, which is a great Rust documentation project. In mdbook, you can edit and run Rust code right from the document (e.g. Hello World)! I really liked this feature, but wanted to be able to send input back to the running process.

demonic-web allows one to do this, and demonic-docs integrates it with html-ized markdown documents. Go ahead and play around and edit any of the code blocks below, and click on the ā€˜ā–¶ā€™ button to run them!

C

#include <stdio.h>

int main(int argc, char** argv) {
    fprintf(stderr, "%s", "Enter your name: ");
    char name[100];
    scanf("%s", name);

    fprintf(stderr, "Hello %s!\n", name);
    return 0;
}

C++

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main(int argc, char** argv) {
    string name;
    cout << "What is your name? ";
    cin >> name;
    cout << "Hello " << name << "!" << endl;
}

Go

package main

import (
    "fmt"
    "bufio"
    "os"
    "strings"
)

func main() {
    fmt.Print("What is your name? ")
    reader := bufio.NewReader(os.Stdin)
    name,_ := reader.ReadString('\n')
    name = strings.Replace(name, "\n", "", -1);
    fmt.Printf("Hello %s!\n", name)
}

Java

import java.util.Scanner;

public class Hello {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        System.out.print("What is your name? ");
        String name = reader.nextLine();
        System.out.println("Hello " + name + "!");
        reader.close();
    }
}

JavaScript (Node.js)

const readline = require('readline');

const readline_interface = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

readline_interface.question('What is your name? ', name => {
    console.log(`Hello ${name}!`);

    readline_interface.close();
    process.exit();
})

Python

def greet():
    name = input('Enter your name: ')
    print('Hello', name)

if __name__ == '__main__':
    greet()

Racket

#lang racket

(define (greet)
  (display "Enter your name: ")
  (printf "Hello, ~a!\n"
          (read-line (current-input-port) 'any)))

(greet)

Ruby

def greet()
  print 'What is your name ? '
  STDOUT.flush
  name = gets
  name = name.chomp
  puts 'Hello ' + name + '!'
end

greet()

Rust

use std::io::stdin;
use std::io::stdout;
use std::io::Write;

fn greet() {
    let mut name = String::new();
    print!("What is your name? ");
    let _ = stdout().flush();
    stdin().read_line(&mut name)
           .ok()
           .expect("Error in reading stdin.");

    if let Some('\n') = name.chars().next_back() {
        name.pop();
    }
    println!("Hello {}!", name);
}

fn main() {
    greet();
}

Shell

#!/bin/sh

greet() {
    read -p "What is your name? " name
    echo "Hello $name"
}

greet

Support and Roadmap

This project aims to allow unmodified markdown files to have editable and runnable code blocks. But there needs to be a way for users to tell which program blocks they want to run and which they donā€™t. Unfortunately, this requires a modification to the markdown files! In this instance, the following markdown code had a ā€œ.norunā€ class addition, which tells demonic not to add a ā€œā–¶ā€ button to the code block.

    {: .norun}
    ```python
    print("Don't run me!")
    ```
print("Don't run me!")

Markdown files converted by Pandoc are the only supported format currently, but Iā€™d like to add lots of others! Iā€™d like to add the following features:

Adding support requires playing around with the resulting DOM structure of each converter and file type, and being able to extract the language and code of each code block.