Initial commit
This commit is contained in:
commit
82d714d8a3
9 changed files with 251 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Nix
|
||||
result*
|
||||
|
||||
# Misc
|
||||
.direnv
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1758427187,
|
||||
"narHash": "sha256-pHpxZ/IyCwoTQPtFIAG2QaxuSm8jWzrzBGjwQZIttJc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "554be6495561ff07b6c724047bdd7e0716aa7b46",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
36
flake.nix
Normal file
36
flake.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
description = "Go Template";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
...
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
go
|
||||
gopls
|
||||
];
|
||||
buildInputs = with pkgs; [];
|
||||
in {
|
||||
devShells.default = pkgs.mkShell {inherit nativeBuildInputs buildInputs;};
|
||||
|
||||
packages.default = pkgs.buildGoModule rec {
|
||||
name = "template";
|
||||
src = ./.;
|
||||
|
||||
inherit buildInputs;
|
||||
|
||||
vendorHash = null;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module git.katkak.dev/katkak/terminal
|
||||
|
||||
go 1.25.0
|
||||
56
main.go
Normal file
56
main.go
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/", http.FileServer(http.Dir("./static")))
|
||||
|
||||
mux.HandleFunc("GET /command/{command}", commandHandler)
|
||||
|
||||
port := 8080
|
||||
log.Printf("Running on port %d\n", port)
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), mux); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func commandHandler(w http.ResponseWriter, r *http.Request) {
|
||||
command := r.PathValue("command")
|
||||
|
||||
log.Printf("Handling command %s for %s\n", command, r.RemoteAddr)
|
||||
|
||||
c, ok := commands[command]
|
||||
if !ok {
|
||||
fmt.Fprintf(w, "Unknown command: %s", command)
|
||||
return
|
||||
}
|
||||
c.Action(w, []string{})
|
||||
}
|
||||
|
||||
type command interface {
|
||||
Usage(w io.Writer)
|
||||
Action(w io.Writer, args []string)
|
||||
}
|
||||
|
||||
var commands = map[string]command{
|
||||
"help": &helpCommand{},
|
||||
}
|
||||
|
||||
type helpCommand struct {}
|
||||
|
||||
func (c *helpCommand) Usage(w io.Writer) {
|
||||
fmt.Fprintf(w, "Usage: help <command>")
|
||||
}
|
||||
|
||||
func (c *helpCommand) Action(w io.Writer, args []string) {
|
||||
fmt.Fprint(w, "Invalid input\r\n")
|
||||
c.Usage(w)
|
||||
}
|
||||
|
||||
26
static/index.html
Normal file
26
static/index.html
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<link rel="stylesheet" href="https://esm.sh/@xterm/xterm/css/xterm.css" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
|
||||
<title>Document</title>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@xterm/xterm": "https://esm.sh/@xterm/xterm",
|
||||
"@xterm/addon-fit": "https://esm.sh/@xterm/addon-fit"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="./index.js" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-terminal></my-terminal>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
59
static/index.js
Normal file
59
static/index.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { Terminal } from "@xterm/xterm";
|
||||
import { FitAddon } from "@xterm/addon-fit";
|
||||
|
||||
class MyTerminalElement extends HTMLElement {
|
||||
|
||||
#terminal;
|
||||
#fitAddon;
|
||||
|
||||
#command = "";
|
||||
|
||||
static #prompt = "$>";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.#terminal = new Terminal({
|
||||
cursorBlink: true,
|
||||
});
|
||||
|
||||
this.#fitAddon = new FitAddon();
|
||||
this.#terminal.loadAddon(this.#fitAddon);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.#terminal.open(this);
|
||||
this.#fitAddon.fit();
|
||||
|
||||
this.#terminal.writeln("Hello from xterm.js");
|
||||
this.#terminal.write(MyTerminalElement.#prompt);
|
||||
|
||||
this.#terminal.onData(async data => {
|
||||
if (data === '\r') {
|
||||
await this.handleCommand();
|
||||
this.#terminal.write("\r\n");
|
||||
this.#terminal.write(MyTerminalElement.#prompt);
|
||||
this.#command = "";
|
||||
} else {
|
||||
this.#terminal.write(data);
|
||||
this.#command += data;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async handleCommand() {
|
||||
const [command, ...args] = this.#command.split(" ");
|
||||
if (command.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(`/command/${command}`);
|
||||
|
||||
this.#terminal.write("\r\n");
|
||||
this.#terminal.write(await response.text());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("my-terminal", MyTerminalElement);
|
||||
|
||||
4
static/style.css
Normal file
4
static/style.css
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
html {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue