Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

mdbook-lang

An mdBook real-time playground for programming languages, executed in the browser with a compiler server deployed by yourself. You can also extend it with some more programming languages.

This is mostly inspired by mdbook rust and mdbook-repl, but it's only limited to rust and some interpreted programming languages through https://play.rust-lang.org or iframe embeded wasm to support such as python,javascript and typescript. Then we can extend it with more programming languages through controled compiler/run server.

#include <iostream>
using namespace std;
int main() {
    cout << "Hello, World!" << endl;
    return 0;
}

All code are editable, resettable, and runnable. You can modify and execute the code directly in the browser to see the output instantly. If you are a teacher assigning exercises to students, you can control cut, copy, and paste actions, as well as disable the browser debugger for a more controlled environment.

Development is ongoing to support many more programming languages in the future.

Usage

This is designed as a preprocessor plugin for mdbook and a compiler server running standalone.

Installation

There are two ways to install mdbook-lang:

You can install it with cargo if you have rust environment:

cargo install mdbook-lang

Or you can download the binary from github page. You should put the binary in your system's PATH.

You can cheeck the instalation with:

mdbook-lang --version

Configuration

After installation, you can configure mdbook-lang in your book's book.toml file through mdbook-lang install to config the plugin usefull for your mdbook.

$ mdbook-lang install /path/to/your/book

This will set the lang preprocessor plugins and the url of compiler server parameters.

For example:

[book]
authors = ["gaoxu.jeffrey"]
language = "en"
multilingual = false
src = "src"
title = "mdbook-lang example"

[preprocessor]

[preprocessor.lang]
command = "mdbook-lang"
server = "http://127.0.0.1:3333/api/v1/build-code"
cpp-enable = true
java-enable = true
go-enable = true
python-enable = true
javascript-enable = true
typescript-enable = true
scheme-enable = true
editable = true
disable-devtool-auto = false
disable-menu = false
clear-log = false
disable-select = false
disable-copy = false
disable-cut = false
disable-paste = false
ace-strict = false

[output]

[output.html]
additional-js = ["jquery.js", "disable-devtool.js", "lang.js"]
additional-css = ["lang.css"]
  • server: The url of compiler server.

I deployed a compiler server, you can modify the value of server use it for test directly.

server = "https://183.205.132.14:3000/playground/api/v1/build-code"

Notice You should open https://183.205.132.14:3000 in your browser and ignore or close the security alert first, othewise you cannot access it when playing your programming language.

  • language-enable: Enable the language for the repl, default value is true.

  • disable-devtool-auto : Disable the browser debugger automatically, default value is false.

  • ace-strict: Enable the strict mode of ace editor, default value is false. When enabled, the editor will not allow the user to cut, copy, and paste code in ACE editor.

Run the compiler server

Only Windows 7/8/10/11 needs install/uninstall Service

All cmd prompt commands need to be run as administrator.

  • insrall the install the mdbook-lang as a service
C:\Windows\System32>mdbook-lang server install --hostname 127.0.0.1 --port 3333

Or use 127.0.0.1 as the default hostname, and 3333 for port:

C:\Windows\System32>mdbook-lang server install

When you donn't need the mdbook-lang service or want to change the hostname and/or port, you should uninstall and re- install it with different hostname and/or port argument(s).

Delete it forever:

mdbook-lang uninstall

If you want change hostname and/or port:

mdbook-lang server uninstall
mdbook-lang server install --hostname 0.0.0.0 --port 3333

Unix like OS and Windows 7/8/10/11

start mdbook-lang compiler server

Administror privilege needed for Windows oS.

You can run the compiler server with:

mdbook-lang server start

Or you can run the compiler server with --hostname or short -n and --port or short -parguments in Unix like OS:

mdbook-lang server start --hostname 127.0.0.1 -port 3333

For Windows

  • start the service
C:\Windows\System32>mdbook-lang server start

or through the OS provided Service manager or Task manager GUI tool.

stop/restart/status subcommands

  • stop server
mdbook-lang server stop
  • restart server
mdbook-lang server restart
  • check server status
mdbook-lang server status

Run the mdbook

mdbook serve -o

Options

norun

norun option will make the codeblock not rendered by the preprocessor. You can use this option if you want to show some code examples that should not be executed, and the language is enabled by language-enable=true.


```java,norun
// java codeblock with norun option
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
```

And it will not be rendered by this preprocessor:

// java codeblock with norun option
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

```java
// java codeblock without norun option
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}
```

And it will be rendered by this preprocessor:

// java codeblock with norun option
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Shortcuts

OSShortcutDescription
WindowsCtrl-EnterRun the code
MacCommand-EnterRun the code
WindowsCtrl-Shift-EnterClear the output
MacCommand-Shift-EnterClear the output

Language Extensions

This preprocessor only recongnizes specific extensions for sepecific language. For example, you can only use use c++ or cpp codeblock for cpp code, use python or py codeblock for python code.

Here is the full list of extensions:

LanguageExtensioncompiler
C++cpp, c++, cclang++
Javajavasun jdk/openjdk
Gogogolang
Pythonpy, pythonpython2, python3(python dir should in the PATH env.)
JavaScriptjs, javascriptnode.js
TypeScriptts, typescriptnode.js, tsc
Schemelisp, schemegambit-scheme(gsi dir should in PATH env.)

In order to to support some langguages, you should install corresponding compilers on compiler server host.

Performance

It is no doubt that the execution of codeblock through browser is really fast compared with in IDEs with additional a slight network delay. And the overload of the compiler server is also not a big problem.

Advanced Usage

nginx reverse proxy to support multiple books

You can deploy multiple books on the same host with only one compiler server and nginx to support mmultiple programming languages.

install nginx

ubuntu

sudo apt-get install nginx

centos

sudo yum install nginx

macos

brew install nginx

windows

choco install nginx

configure nginx

sudo vim /etc/nginx/conf.d/mdbook-lang.conf

and add the following content:

# /etc/nginx/conf.d/mdbook.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    # nginx listen port
    listen 3000;
    server_name 0.0.0.0;

    # compiler server
    location /playground/{
    	proxy_pass http://127.0.0.1:3333/;
    }
    # java object oriented programming mdbook
    location /joop/{
        proxy_pass http://127.0.0.1:2000/;
    }
    location /joop/__livereload{
        proxy_pass http://127.0.0.1:2000/__livereload/;
    }

    # rust-course mdbook
    location /rust-course/{
        proxy_pass http://127.0.0.1:2001/;
    }
    location /rust-course/__livereload{
        proxy_pass http://127.0.0.1:2001/__livereload/;
    }
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}

start nginx

sudo nginx -s reload

start compiler server

mdbook-lang server --hostname 127.0.0.1 --port 3333

start mdbook

$ cd /path/to/joop/
$ mdbook serve --hostname 127.0.0.1  --port 2000 > joop-mdbook.log 2> &1 &
$ cd /path/to/rust-course/
mdbook serve --hostname 127.0.0.1 --port 2001 > rust-course.log > 2&1 &

modify book.toml's server option

server = "http://183.205.132.14:3000/playground/api/v1/build-code"

access mdbook

sandbox

install firejail

ubuntu

sudo apt-get install firejail

centos

sudo yum install firejail

macos

brew install firejail

configure firejail

sudo vim /etc/firejail/mdbook-lang-server.profile

and add the following content:

# /etc/firejail/mdbook-lang-server.profile
include disable-common.inc
# include disable-exec.inc
# noexec ${HOME}
noexec ${RUNUSER}
noexec /dev/shm
noexec /var

# must be canceled for c/c++ execute output.exe in /tmp
# noexec /tmp

include disable-passwdmgr.inc
include disable-programs.inc
quiet

net none

nodbus
nodvd
nogroups
nonewprivs
noroot
nosound
notv
nou2f
novideo
protocol inet,inet6
seccomp
shell none
# tracelog

disable-mnt
private
# for debug porpose
# private-bin ls

# allow c/c++ tools chain
private-bin mdbook-lang
private-bin clang++
private-bin ld

# allow java tools chain
private-bin java
private-bin javac

# allow python tools chain
private-bin python2
private-bin python3
private-bin python

# allow go tools chain
private-bin go

# allow javascript/typescript tools chain
private-bin node
private-bin tsc

# allow lisp/scheme tools chain
private-bin scheme-r5rs

# allow c/c++ output executable
private-bin output.exe

# must be canceled for java/javac
# private-lib

blacklist /opt
blacklist /etc/nginx
blacklist /etc/firejail
blacklist /etc

blacklist /sbin
# checked for java,c/c++,
blacklist /bin
# for python interpreter
# blacklist /usr/bin
blacklist /usr/sbin
blacklist /usr/libexec
blacklist /usr/local/sbin
blacklist /usr/local/lib
blacklist /usr/local/libexec
blacklist /usr/libexec/firejail
blacklist /usr/libexec/firejail/firejail-config
blacklist /usr/libexec/firejail/firejail-profile
blacklist /usr/libexec/firejail/firejail-shell
blacklist /usr/libexec/firejail/firejail-shell-wrapper
blacklist /usr/libexec/firejail/firejail

configure envs

sudo vim ~/.bashrc

and add the following content:

export MDBOOKLANG_SERVER_SANDBOX_CMD="firejail"
export MDBOOKLANG_SERVER_SANDBOX_ARGS="--profile=/etc/firejail/mdbook-lang-server.profile:--quiet"

Note: sandbox is for single or multiple books, local or remote server is ok.

Enjoy it!

firejail Configuration

Adding Whitelists

If your deployed Python programming environment is not in the system path but under ${HOME}, in addition to adding it to the PATH environment variable in $HOME/.bash, you also need to install the required packages:

  • If you use the system Python environment and install packages as a non-root user, the extra packages will be installed at: ${HOME}/.local/lib/python3.10/site-packages
$ python -m pip install numpy

You need to add the following statement at the end of your firejail configuration file (note the Python version number):

whitelist ${HOME}/.local/lib/python3.10/site-packages

Adding Compiler Whitelists

If you have installed other compilers, add the following to your firejail configuration file:

private-bin your-compiler-file-name

C/C++

C/C++ is a system programming that lets you write programs that can run on any platform. It's a powerful language that can be used to write low-level programs, such as operating systems, drivers, and games. It's also a great language for learning programming.

#include <iostream>
using namespace std;
int main() {
    cout << "Hello, World!" << endl;
    return 0;
}

Go

Go is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It is syntactically similar to C, but with memory safety, garbage collection, structural typing, and CSP-style concurrency.

Go is often used for system programming, network programming, and distributed systems. It is also used for building web applications, microservices, and cloud-native applications.

package main
import "fmt"
func main() {
	fmt.Println("Hello, World!")
}

Java

Java is a multi-paradigm programming language that supports object-oriented, imperative, and functional programming styles. It is a compiled language, which means that code written in Java is compiled into bytecode that can run on any Java virtual machine (JVM) regardless of the underlying computer architecture.

Java is used for developing a wide range of applications, including desktop applications, web applications, mobile applications, and enterprise applications. It is also used for developing large-scale distributed systems, such as the internet, and for developing real-time systems, such as video games.

The ACE editor for Java is a simple text-based interface that allows you to write and run Java code. The compiler/run server use the javac command to compile your code, and the java command to run it. The compiler/run server will find the public class to save proper file name, and find the main class and main method to run it.

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

You cannot write multiple public class in the same file, otherwise , the compiler will throw an error.

For example, the following codes will throw an errors:

public class HelloWorld {
    public static void main(String[] args) {
        new Fibonacci().run(10);
    }
}

public class Fibonacci {
    public void run(int n) {
        int n = 10;
        int a = 0, b = 1;
        for (int i = 0; i < n; i++) {
            System.out.println(a);
            int temp = a;
            a = b;
            b = temp + b;
        }
    }
}
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

public class Sum {
     public static void main(String[] args) {
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        System.out.println("Sum of first 100 numbers is: " + sum);
    }
}

Additionaly, the compiler/run server will find the main class to run it. If you have multiple main class, the compiler/run server will run the first main class found int the order of the class name.

class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

class Sum {
     public static void main(String[] args) {
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        System.out.println("Sum of first 100 numbers is: " + sum);
    }
}

The output of the above code will be:

Hello, World!

Python

Python is a high-level, interpreted programming language that is widely used for web development, data analysis, artificial intelligence, and automation. It is known for its simplicity, readability, and versatility.

print("Hello, World!")

Javascript

JavaScript is a high-level, interpreted programming language that is primarily used for creating interactive web pages. It is a versatile language that can be used for both front-end and back-end development.

console.log("Hello, World!");

Typescript

TypeScript is a strongly typed, object-oriented programming language that is designed to be compiled into JavaScript. It is a superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code.

TypeScript adds static typing to JavaScript, which means that variables must be declared with a specific type. This helps to catch errors at compile time, rather than at runtime.

let person: { name: string; age: number; isStudent: boolean } = {

    name: "John",
    age: 30,
    isStudent: true,
}
console.log(person);

Scheme

Scheme is a programming language that is designed to be easy to learn and use. It is a dialect of Lisp, which is a family of programming languages. Scheme is a functional programming language, which means that it uses functions to perform computations.

;scheme,lisp
(define (greet-world)
  (let ((southern-germany "Grüß Gott!")
        (chinese "世界,你好")
        (english "World, hello"))
    (let ((regions (list southern-germany chinese english)))
      (for-each (lambda (region)
                  (display region)
                  (newline))
                regions))))
(greet-world)