<file_sep>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {

  int status;
  pid_t pid = fork();

  /* Ignore signals from keyboard */
  signal(SIGINT, SIG_IGN);
  signal(SIGTSTP, SIG_IGN);
  signal(SIGQUIT, SIG_IGN);

  if (pid == 0) {

    char ppid[12];
    sprintf(ppid, "%d", getppid());
    char *aargv[4] = {"alien-js", ppid, NULL};
    execvp( "alien-js", aargv );
    printf("Count not launch alien shell...\n");
    exit(0);

  } else {

    while (wait(&status) != pid);
    return status;

  }

}
<file_sep>cmake_minimum_required(VERSION 3.10)

project(Alien VERSION 0.0.1)
add_executable(alien alien.c)

install(TARGETS alien RUNTIME DESTINATION bin)
<file_sep>const REPL = require("./repl");
const keys = require("@alien.sh/repl/keys");
const builtins = require("./builtins");
const eventEmitter = require("events");
const { generate } = require("./parser/index")({ scope: { builtins } });

const scope = {
  builtins,
  async pipe(...args) {
    const procs = [];
    for (const [index, arg] of Object.entries(args)) {
      const i = Number(index);
      const stdio =
        i == args.length - 1 ? ["pipe", "inherit", "inherit"] : "pipe";
      const proc = await arg.eval(scope, stdio);
      procs[i] = proc;
      if (i > 0) {
        procs[i - 1].stdout.pipe(proc.stdin);
      }
    }
    const result = await procs[procs.length - 1].results();
    await Promise.all(procs);
    console.log(result);
  },
  cd(path) {
    try {
      process.chdir(path);
    } catch {
      console.log(`Cannot cd to ${path}`);
    }
  },
  exit() {
    process.exit(0);
  }
};

const SIGTSTP = 18;

const handle = async (core, line) => {
  const atom = await core.generate(line);
  const proc = await atom.eval(scope, "inherit");
  if (proc && proc.results) {
    return new Promise(async resolve => {
      core.signals.on(SIGTSTP, function() {
        console.log("meow");

        resolve();
      });
      const results = await proc.results();
      return resolve(results);
    });
  }
};

const start = core => {
  const { stdin, stdout } = process;
  core.repl = new core.REPL({
    core,
    stdin,
    stdout,
    prompts: { prompt: "\ue36e >" }
  });
  for (const plugin of core.plugins) {
    plugin(core);
  }
};

const signals = new eventEmitter();

const core = {
  start,
  handle,
  scope,
  generate,
  REPL,
  keys,
  signals,
  onBeforePrint: [],
  onBeforeProcess: [],
  onSig: []
};

module.exports = core;
<file_sep># Alien

Alien Shell

## Installation

There are no installation instructions because this isn't ready for general use. I will provide instructions when the below issues are fixed.

## Known issues / TODO

- [ ] Ctrl+c, Ctrl+z, ... does not work
- [X] Tab completion is buggy
- [ ] No history
- [X] When in a process, keyboard input does not work

## Screenshots

![banner](https://github.com/alien-sh/alien/raw/master/alien.png)

Commands:

![commands](https://github.com/alien-sh/alien/raw/master/screenshot.png)
<file_sep>const patterns = {
  string: /^"(?:[^"]|\\")*"/,
  backtick: /^`/,
  left_paren: /^[(]/,
  right_paren: /^[)]/,
  number: /^([+-]?(\d+(\.\d+)?)|(\.\d+))(?= |\n|$)/,
  boolean: /^(true|false)(?=[ \n()]|$)/,
  date: /^\d{4}-\d{2}-\d{2}(?=[ \n()]|$)/,
  symbol: /^[^ \r\n\t()]+/i,
  newline: /^\r?\n/,
  space: /^ +/
};

module.exports = patterns;
<file_sep>#!/usr/bin/env node

const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");

const buildDir = path.join(__dirname, "build");
fs.mkdirSync(buildDir, { recursive: true }, () => {});

const prefix = process.argv[2];

execSync(`cmake -DCMAKE_INSTALL_PREFIX:PATH=${prefix} ..`, { cwd: buildDir });
execSync("cmake --build . --target install", { cwd: buildDir });
<file_sep>const repl = require("@alien.sh/repl");

const hasEqualParens = str =>
  (str.match(/\(/g) || []).length == (str.match(/\)/g) || []).length;

class AlienRepl extends repl {
  constructor({ core, ...rest }) {
    super(rest);
    this.core = core;
    this.keyEaters["\r"] = [
      function(key) {
        if (this.isBusy) return;
        if (this.currentInput && hasEqualParens(this.currentInput)) {
          this.stdout.write("\n");
          this.processInput();
        } else {
          this.insertAtCursor(key);
        }
      }
    ];
  }
  preprint() {
    for (const hook of this.core.onBeforePrint) {
      hook.call(this);
    }
  }
  async processInput() {
    let src = this.currentInput;
    for (const hook of this.core.onBeforeProcess) {
      src = hook.call(this, src);
    }
    this.y = 0;
    this.x = 0;
    this.currentInput = "";
    this.currentOutput = "";
    this.stdout.write("\n");
    this.isBusy = true;
    this.stdin.pause();
    this.stdin.setRawMode(false);
    await this.core.handle(this.core, src);
    this.stdin.setRawMode(true);
    this.stdin.resume();
    this.isBusy = false;
    this.stdout.write("\n");
    this.preprint();
    this.print();
  }
}

module.exports = AlienRepl;
<file_sep>#!/usr/bin/env sh

version="0.0.11"

info() {
  echo -e "\e[92m$1\e[0m"
}

error() {
  echo -e "\e[91mError! $1\e[0m"
}

run() {
  command="$@"
  if [ -z ${noroot+x} ]; then
    if [ -x "$(command -v sudo)" ]; then
      sudo $command
    else
      su root -c "$command"
    fi
  else
    $command
  fi
}

checkdeps() {
  if ! { [ -x "$(command -v fetch)" ] || [ -x "$(command -v wget)" ] || [ -x "$(command -v curl)" ]; }; then
    error "This script needs one of: fetch, wget or curl"
    exit 1
  elif ! { [ -x "$(command -v npm)" ] && [ -x "$(command -v node)" ]; }; then
    error "This script needs npm and node"
    exit 1
  elif ! [ -x "$(command -v cmake)" ]; then
    error "This script needs cmake"
    exit 1
  elif ! [ -x "$(command -v tar)" ]; then
    error "This script needs tar"
    exit 1
  elif ! [ -x "$(command -v whoami)" ]; then
    error "This script needs whoami"
    exit 1
  fi
}

getvars() {
  bundle="bundle.tar.gz"
  dirname="alien*"
  tarball="https://github.com/alien-sh/alien/archive/v$version.tar.gz"
  if [ -d "./.git" ]; then
    checkout="YES"
  fi
}

getargs() {
  while [ "$#" -gt 0 ]
    do
      case "$1" in
        -p|--prefix)
        shift
        prefix="$1"
        ;;
        -p=*|--prefix=*)
        prefix="${1#*=}"
        ;;
        -np|--no-plugins)
        noplugins="YES"
        ;;
        -nr|--no-root)
        noroot="YES"
        ;;
        *)
        error "Unknown option '$key'"
        exit 1
        ;;
      esac
      shift
    done
}

checkargs() {
  if [ -z ${prefix+x} ]; then
    info "Prefix not set, setting to /usr/local"
    prefix="/usr/local"
  fi
}

download() {
  if ! [ -z ${checkout+x} ]; then
    info "Skipping download"
    return 0
  fi
  info "Downloading: $tarball"
  if [ -x "$(command -v fetch)" ]; then
    fetch $tarball -o $bundle
  elif [ -x "$(command -v wget)" ]; then
    wget $tarball -O $bundle
  elif [ -x "$(command -v curl)" ]; then
    curl $tarball --output $bundle
  fi
}

maketemp() {
  if ! [ -z ${checkout+x} ]; then
    info "Skipping temp dir creation"
    return 0
  fi
  tmpdir=$(mktemp -d -t al-XXXXXXXXXX)
  info "Created temp dir: $tmpdir"
  cd $tmpdir
}

untar() {
  if ! [ -z ${checkout+x} ]; then
    return 0
  fi
  tar xzf $bundle
  cd $dirname
}

install() {
  if ! [ -z ${checkout+x} ]; then
    info "Installing from checkout"
  fi
  info "Installing dependencies"
  npm install
  info "Installing in $prefix"
  run "npm install --prefix $prefix -g ."
  run "node build.js $prefix"
}

homesetup() {
  cd ~
  if ! [ -d ".alien" ]; then
    mkdir ".alien"
  fi
  if ! [ -z ${noplugins+x} ]; then
    info "Skipping plugin install"
    return 0
  fi
  cd ".alien"
  if ! [ -f "package.json" ]; then
    configdir="$(whoami)-alien-config"
    mkdir $configdir
    cd $configdir
    npm init -y
    mv "package.json" ..
    cd ..
    rm -rf $configdir
  fi
  npm i -S "@alien.sh/core-plugins"
  echo 'module.exports = [require("@alien.sh/core-plugins")];' > "plugins.js"
}

main() {
  checkdeps
  getvars
  getargs $@
  checkargs
  maketemp
  download
  untar
  install
  homesetup
  info "Install done."
}

main $@
