Skip to content

Qwiery/qwiery-vue-terminal

Repository files navigation

Vue Terminal Component

Install with npm install @orbifold/vue-terminal --save

Some internals

The terminal consists of three visual parts:

  • the optional banner: only shown at the start of a session
  • the output: the part above the input growing with each interaction. The output can be of three types:
    • output coming some processing
    • the input given being repeated (before showing the process output)
    • an error/warning/info: looks different from the other two in order to draw attention
  • the input: where you type stuff, but if you use u/down arrows there is also input coming from the terminal itself. Auto-completion would be another case.

The terminal accept various input types and accodingly there are different types of 'messages' handed over to processing. The simplest case is text but you could also drag-drop and image. The terminal receives various types of events from the controller:

  • input: something changing the input line (autocomplete, history navigation...)
  • output: something to be shown in the output stack
  • command: not anything visual, but an instruction to do something on the UI level (e.g. clear the terminal).

The component tries hard to makes sense of input and output, to render things appropriately and make it flexible for various use cases. For example, a custom command needs to return a CommandMessage but if a string or a different message type is returned (by the custom function) it will be handled nevertheless.

Messages

The messages convey different types of information (code, image, text...) and they can carry additional information (a payload). All the predefined message types sit in the @orbifold/entities package, but you can easily create your own. There is also a MessageFactory acting as a gateway to diverse

How to handle input?

Hook up the executor property

<template>
<Terminal :executor="executor" />
</templare>
<script setup lang="ts">
import { TextMessage} from "@orbifold/entities";
function executor(input: Message) {
	 if (input instanceof TextMessage) {
    return"you said " + input.text;
  }
}
</script>

The reason why the input parameter is not a simple string is because the terminal can handle code snippets, images, whatnot. If you are only interested in dealing with simple textual input (say a bot), you can simply use the TextMessage for everything.

The function can be async if necessary. Internally the return is converted to a TextMessage if a string is given. If you change the function to the following, the result will be eactly the same:

import { TextMessage} from "@orbifold/entities";
function executor(input: Message) {
	 if (input instanceof TextMessage) {
    return TextMessage.fromString("you said " + input.text);
  }
}

Returning messages rather than a string does give more flexibility. For example, a message can have annotations, these are arbitrary indications and, for instance, the color key will tell the renderer to display the text in purple:

import * from '@orbifold/entities';
function executor(input:string){
  const message = TextMessage.fromString("You gave: " + input);
  message.annotations ={
    color: "purple"
  }
 return message;
}

If you wish to return an error (rendered by default in red):

import * from '@orbifold/entities';
function executor(input:string){
 return ErrorMessage.fromString("This isn't right 🫤")
}

How handle commands?

A command starts with an exclamation mark, for example !clear. You can, however, use an alias (redirect or shortcut) to bypass this. See the explanation below.

Commands can be defined via the commands prop:

<template> 
    <Terminal :commands="commands"/> 
</template>
<script setup lang="ts">
const commands = {
  ls: () => {
    return TextMessage.fromString("Lists the files in the current directory.");
  },
};
</script>

Prefix

The prompt or prefix can be set with the prefix prop. It's a string or a function, so it can be dynamic. The function receives the controller as a paramter, so you can access pretty much anything (the input history, the commands...) you need to provide a dynamic prefix.

By default the prefix is not kept in the output. If you wish to do so, set the keepPrefix prop to true.

To have the time as prefix:

<template>
  <Terminal     
     :prefix="prefix"     
    />
</Terminal>    
<script setup land="ts">
const prefix = ()=> new Date().toLocaleTimeString() + " > ";
</script>

How to define an alias?

An alias or redirect will convert some string input to something else. For instance, the command clear will clear the terminal but this is an alias for !clear since commands should normally be prefixed with !.

Style

The various style classes can be seen in assets\style.css file and you simply need to redefine them in your application.

Feedback

This component is part of the Qwiery framework to help jump-start your graph visualizations. It's neither bug-free nor complete and if you find something isn't as expected you can report it or contact us:

Consulting and Custom Development

You can use any of the links above to contact us with respect to custom development and beyond. We have more than 20 years experience with everything graphs.

License

MIT License

Copyright (c) 2024 Orbifold B.V.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.