TerminalComponentBrainfk

by Tales Miranda

HTML

<div id="console" class="console">
  <div id="history" class="history">
    <div class="line" v-for="text, index of history" :key="index">{{text}}</div>
  </div>
  <div class="input-area" @keydown.Enter="commitLine">
    <div class="prompt">{{prompt}}</div>
    <input class="input-line" v-model="inputLine" />
  </div>
</div>

CSS

.console {
  background-color: #eee;
  border: 1px solid #ccc;
  font-family: monospace;
}

.history .line {
  white-space: pre-wrap;
}

.input-area {
  border-top: 3px double #ccc;
  display: flex;
}

.prompt {
  white-space: pre-wrap;
}

.input-line {
  width: 100%;
  padding: 0;
  border: 0;
  background-color: transparent;
  font-family: monospace;
}

JavaScript

const app = new Vue({
  el: '#console',
  data: {
    inputLine: '',
    history: [],
    prompt: '? ',
    inputHandler: handleInput,
  },
  methods: {
    commitLine() {
      const input = this.inputLine
      this.inputLine = ''
      this.outputLine(input)
      // here we call some handler method
      this.inputHandler(input)
    },
    clear() {
      this.history = []
    },
    output(text) {
      text = (text || '').toString()
      const lastNewLine = text.lastIndexOf('\n')
      if (lastNewLine >= 0) {
        this.outputLine(text.slice(0, lastNewLine))
        this.prompt = text.slice(lastNewLine + 1)
      } else {
        this.prompt += text
      }
    },
    outputLine(text) {
      text = this.prompt + (text || '')
      this.history.push(text)
      this.prompt = ''
    }
  },
})

const state = {
  cells: {
    /* 0: 65,
    3: 42,
    17: 99,
    64: 77, */
  },
  dataPointer: 0,
  inputSink: null,
}

function handleInput(text) {
  text = text || ''
  if (state.inputSink) {
  	state.inputSink(text+'\n')
    state.inputSink = null
    resume()
  } else if (text.match(/!c\b/)) {
    app.clear()
    app.output('? ')
  } else if (text.match(/!s\b/)) {
    printCells()
    app.output('? ')
  } else if (text.match(/!r\b/)) {
    state.cells = {}
    state.dataPointer = 0
    app.output('? ')
 } else {
    execute(text)
  }

  function execute(program) {
    state.program = program
    state.programCounter = 0
    state.inputBuffer = null
    resume()
  }
  
  function resume() {
    state.running = true
    for (; state.programCounter < state.program.length && state.running; state.programCounter++) {
      executeOp(state.program[state.programCounter])
    }
    if (!state.running) {
    	return
    }
    state.running = false
  	app.output('\n? ')  
  }

  function executeOp(opCode) {
    switch (opCode) {
      case '.':
        app.output(String.fromCharCode(state.cells[state.dataPointer] | 0))
        break;
      case ',':
      	if...