commit 82d714d8a3ba9670f967f24248891574303e4bda Author: ktkk Date: Wed Sep 24 10:04:30 2025 +0000 Initial commit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5adaf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Nix +result* + +# Misc +.direnv diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..4d1227e --- /dev/null +++ b/flake.lock @@ -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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..eb94bec --- /dev/null +++ b/flake.nix @@ -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; + }; + } + ); +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0b57841 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.katkak.dev/katkak/terminal + +go 1.25.0 diff --git a/main.go b/main.go new file mode 100644 index 0000000..f9c3812 --- /dev/null +++ b/main.go @@ -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 ") +} + +func (c *helpCommand) Action(w io.Writer, args []string) { + fmt.Fprint(w, "Invalid input\r\n") + c.Usage(w) +} + diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..5f602c2 --- /dev/null +++ b/static/index.html @@ -0,0 +1,26 @@ + + + + + + + + + + Document + + + + + + + + + diff --git a/static/index.js b/static/index.js new file mode 100644 index 0000000..995adde --- /dev/null +++ b/static/index.js @@ -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); + diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..603ac51 --- /dev/null +++ b/static/style.css @@ -0,0 +1,4 @@ +html { + background-color: #000000; +} +