This commit is contained in:
Zhi Wang 2022-01-04 21:21:21 -05:00
parent eedf025867
commit aa283ec188
4 changed files with 73 additions and 70 deletions

View File

@ -12,11 +12,12 @@
<script src="xterm-addon-attach.js"></script> <script src="xterm-addon-attach.js"></script>
<script src="xterm-addon-fit.js"></script> <script src="xterm-addon-fit.js"></script>
<script src="xterm-addon-web-links.js"></script> <script src="xterm-addon-web-links.js"></script>
<script src="main.js"></script>
<script src="main.js"></script>
<link rel="stylesheet" href="xterm.css" /> <link rel="stylesheet" href="xterm.css" />
<link rel="stylesheet" href="main.css" /> <link rel="stylesheet" href="main.css" />
<title>Websocket Terminal</title> <title>Websocket Terminal</title>
</head> </head>
@ -28,31 +29,28 @@
<script> <script>
term = createTerminal(); term = createTerminal();
// print something to test output and scroll // print something to test output and scroll
var str = [ var str = [
' Xterm.js is the frontend component that powers many terminals including', ' Xterm.js is the frontend component that powers many terminals including',
' \x1b[3mVS Code\x1b[0m, \x1b[3mHyper\x1b[0m and \x1b[3mTheia\x1b[0m!', ' \x1b[3mVS Code\x1b[0m, \x1b[3mHyper\x1b[0m and \x1b[3mTheia\x1b[0m!',
'', '',
' ┌ \x1b[1mFeatures\x1b[0m ──────────────────────────────────────────────────────────────────┐', ' ┌ \x1b[1mFeatures\x1b[0m ──────────────────────────────────────────────────────────────────┐',
' │ │', ' │ │',
' │ \x1b[31;1mApps just work \x1b[32mPerformance\x1b[0m │', ' │ \x1b[31;1mApps just work \x1b[32mPerformance\x1b[0m │',
' │ Xterm.js works with most terminal Xterm.js is fast and includes an │', ' │ Xterm.js works with most terminal Xterm.js is fast and includes an │',
' │ apps like bash, vim and tmux optional \x1b[3mWebGL renderer\x1b[0m │', ' │ apps like bash, vim and tmux optional \x1b[3mWebGL renderer\x1b[0m │',
' │ │', ' │ │',
' │ \x1b[33;1mAccessible \x1b[34mSelf-contained\x1b[0m │', ' │ \x1b[33;1mAccessible \x1b[34mSelf-contained\x1b[0m │',
' │ A screen reader mode is available Zero external dependencies │', ' │ A screen reader mode is available Zero external dependencies │',
' │ │', ' │ │',
' │ \x1b[35;1mUnicode support \x1b[36mAnd much more...\x1b[0m │', ' │ \x1b[35;1mUnicode support \x1b[36mAnd much more...\x1b[0m │',
' │ Supports CJK 語 and emoji \u2764\ufe0f \x1b[3mLinks\x1b[0m, \x1b[3mthemes\x1b[0m, \x1b[3maddons\x1b[0m, \x1b[3mtyped API\x1b[0m │', ' │ Supports CJK 語 and emoji \u2764\ufe0f \x1b[3mLinks\x1b[0m, \x1b[3mthemes\x1b[0m, \x1b[3maddons\x1b[0m, \x1b[3mtyped API\x1b[0m │',
' │ ^ Try clicking italic text │', ' │ ^ Try clicking italic text │',
' │ │', ' │ │',
' └────────────────────────────────────────────────────────────────────────────┘', ' └────────────────────────────────────────────────────────────────────────────┘',
'' ''
].join('\n\r'); ].join('\n\r');
term.writeln(str);
term.writeln(str);
term.writeln(str);
term.writeln(str);
</script> </script>
</body> </body>

View File

@ -14,12 +14,15 @@
.xterm-viewport.xterm-viewport { .xterm-viewport.xterm-viewport {
scrollbar-width: thin; scrollbar-width: thin;
} }
.xterm-viewport::-webkit-scrollbar { .xterm-viewport::-webkit-scrollbar {
width: 10px; width: 10px;
} }
.xterm-viewport::-webkit-scrollbar-track { .xterm-viewport::-webkit-scrollbar-track {
opacity: 0; opacity: 0;
} }
.xterm-viewport::-webkit-scrollbar-thumb { .xterm-viewport::-webkit-scrollbar-thumb {
min-height: 20px; min-height: 20px;
background-color: #ffffff20; background-color: #ffffff20;

View File

@ -1,38 +1,40 @@
function createTerminal() { function createTerminal() {
// vscode-snazzy https://github.com/Tyriar/vscode-snazzy // vscode-snazzy https://github.com/Tyriar/vscode-snazzy
var baseTheme = { // copied from xterm.js website
foreground: '#eff0eb', var baseTheme = {
background: '#282a36', foreground: '#eff0eb',
selection: '#97979b33', background: '#282a36',
black: '#282a36', selection: '#97979b33',
brightBlack: '#686868', black: '#282a36',
red: '#ff5c57', brightBlack: '#686868',
brightRed: '#ff5c57', red: '#ff5c57',
green: '#5af78e', brightRed: '#ff5c57',
brightGreen: '#5af78e', green: '#5af78e',
yellow: '#f3f99d', brightGreen: '#5af78e',
brightYellow: '#f3f99d', yellow: '#f3f99d',
blue: '#57c7ff', brightYellow: '#f3f99d',
brightBlue: '#57c7ff', blue: '#57c7ff',
magenta: '#ff6ac1', brightBlue: '#57c7ff',
brightMagenta: '#ff6ac1', magenta: '#ff6ac1',
cyan: '#9aedfe', brightMagenta: '#ff6ac1',
brightCyan: '#9aedfe', cyan: '#9aedfe',
white: '#f1f1f0', brightCyan: '#9aedfe',
brightWhite: '#eff0eb' white: '#f1f1f0',
}; brightWhite: '#eff0eb'
};
const term = new Terminal({ const term = new Terminal({
fontFamily:`'Fira Code', monospace`, fontFamily: `'Fira Code', monospace`,
fontSize:12, fontSize: 12,
theme:baseTheme, theme: baseTheme,
convertEol: true,
}); });
term.open(document.getElementById('terminal_view')); term.open(document.getElementById('terminal_view'));
term.resize(120, 36); term.resize(120, 36);
const weblinksAddon = new WebLinksAddon.WebLinksAddon(); const weblinksAddon = new WebLinksAddon.WebLinksAddon();
term.loadAddon(weblinksAddon) term.loadAddon(weblinksAddon);
// fit the xterm viewpoint to parent element // fit the xterm viewpoint to parent element
const fitAddon = new FitAddon.FitAddon(); const fitAddon = new FitAddon.FitAddon();
@ -40,10 +42,9 @@ function createTerminal() {
fitAddon.fit(); fitAddon.fit();
// create the websocket and connect to the server // create the websocket and connect to the server
const ws_uri = "ws://" + window.location.host + "/ws" const ws_uri = "ws://" + window.location.host + "/ws";
const socket = new WebSocket(ws_uri) const socket = new WebSocket(ws_uri);
console.log("Attempting to connect to" + ws_uri); const attachAddon = new AttachAddon.AttachAddon(socket);
const attachAddon = new AttachAddon.AttachAddon(socket)
term.loadAddon(attachAddon); term.loadAddon(attachAddon);
return term; return term;

21
main.go
View File

@ -2,9 +2,10 @@ package main
import ( import (
"fmt" "fmt"
"strings"
"net/http" "net/http"
"net/url" "net/url"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
@ -12,11 +13,11 @@ import (
var host *string = nil var host *string = nil
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
ReadBufferSize : 4096, ReadBufferSize: 4096,
WriteBufferSize: 4096, WriteBufferSize: 4096,
CheckOrigin: func(r *http.Request) bool { CheckOrigin: func(r *http.Request) bool {
org := r.Header.Get("Origin") org := r.Header.Get("Origin")
h,err := url.Parse(org) h, err := url.Parse(org)
if err != nil { if err != nil {
return false return false
@ -32,9 +33,9 @@ var upgrader = websocket.Upgrader{
// handle websockets // handle websockets
func wsHandler(w http.ResponseWriter, r *http.Request) { func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w,r, nil) conn, err := upgrader.Upgrade(w, r, nil)
if err!= nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
@ -44,12 +45,12 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
for { for {
msgType, p, err := conn.ReadMessage() msgType, p, err := conn.ReadMessage()
if err!= nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
if err := conn.WriteMessage(msgType, p); err!= nil { if err := conn.WriteMessage(msgType, p); err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
@ -57,7 +58,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
} }
// return files // return files
func fileHandler (c *gin.Context, fname string) { func fileHandler(c *gin.Context, fname string) {
// if the URL has no fname, c.Param returns "/" // if the URL has no fname, c.Param returns "/"
if fname == "/" { if fname == "/" {
fname = "/index.html" fname = "/index.html"
@ -76,13 +77,13 @@ func fileHandler (c *gin.Context, fname string) {
} }
} }
func main () { func main() {
rt := gin.Default() rt := gin.Default()
rt.SetTrustedProxies(nil) rt.SetTrustedProxies(nil)
rt.LoadHTMLGlob("assets/*.html") rt.LoadHTMLGlob("assets/*.html")
rt.GET("/*fname", func(c *gin.Context){ rt.GET("/*fname", func(c *gin.Context) {
fname := c.Param("fname") fname := c.Param("fname")
// ws is a special case to create a new websocket // ws is a special case to create a new websocket