diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..46aca19 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,37 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs + +name: Deploy + +on: + push: + branches: ['main'] + +jobs: + build: + runs-on: ubuntu-latest + environment: DEPLOYMENT + + steps: + - uses: actions/checkout@v3 + - name: Setup environment + run: | + ./.vscode/setup.sh + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + + - name: Build with Decky CLI + run: | + ./.vscode/build.sh + + - name: Upload a Build Artifact + uses: actions/upload-artifact@v2 + with: + # Artifact name + name: DeckyTerminal Build + # A file, directory or wildcard pattern that describes what to upload + path: out/*.zip diff --git a/defaults/defaults.txt b/defaults/defaults.txt deleted file mode 100644 index ebf140b..0000000 --- a/defaults/defaults.txt +++ /dev/null @@ -1,13 +0,0 @@ -If you have plain-text json configs, theme templates, or templates for usage for your plugin of any description you should have those files be in here. -Those files will be pulled into the zip during the build process and included with the upload. Example: CssLoader with it's themes in "default/themes" would have the "themes" folder will be added alongside with the dist folder, main.py, LICENSE and README files in the subfolder of the zip containing the plugin. -Files can also be put in here such as a config, just keep in mind that they this directory cannot be utilized to put files in arbitrary locations, just within the extracted root folder of the plugin, ex: CssLoader has "defaults/themes/..." setup in it's repo, but when packaged to go to the store, the file structure will be: - -- LICENSE -- README -- dist - - index.js -- main.py -- package.json -- plugin.json -- themes - - exampletheme.css \ No newline at end of file diff --git a/defaults/py_modules/decky_terminal/__init__.py b/py_modules/decky_terminal/__init__.py similarity index 100% rename from defaults/py_modules/decky_terminal/__init__.py rename to py_modules/decky_terminal/__init__.py diff --git a/defaults/py_modules/decky_terminal/common.py b/py_modules/decky_terminal/common.py similarity index 100% rename from defaults/py_modules/decky_terminal/common.py rename to py_modules/decky_terminal/common.py diff --git a/defaults/py_modules/decky_terminal/nato.py b/py_modules/decky_terminal/nato.py similarity index 100% rename from defaults/py_modules/decky_terminal/nato.py rename to py_modules/decky_terminal/nato.py diff --git a/defaults/py_modules/decky_terminal/terminal.py b/py_modules/decky_terminal/terminal.py similarity index 100% rename from defaults/py_modules/decky_terminal/terminal.py rename to py_modules/decky_terminal/terminal.py diff --git a/defaults/py_modules/websockets/LICENSE b/py_modules/websockets/LICENSE similarity index 100% rename from defaults/py_modules/websockets/LICENSE rename to py_modules/websockets/LICENSE diff --git a/defaults/py_modules/websockets/__init__.py b/py_modules/websockets/__init__.py similarity index 100% rename from defaults/py_modules/websockets/__init__.py rename to py_modules/websockets/__init__.py diff --git a/defaults/py_modules/websockets/__main__.py b/py_modules/websockets/__main__.py similarity index 100% rename from defaults/py_modules/websockets/__main__.py rename to py_modules/websockets/__main__.py diff --git a/defaults/py_modules/websockets/auth.py b/py_modules/websockets/auth.py similarity index 100% rename from defaults/py_modules/websockets/auth.py rename to py_modules/websockets/auth.py diff --git a/defaults/py_modules/websockets/client.py b/py_modules/websockets/client.py similarity index 100% rename from defaults/py_modules/websockets/client.py rename to py_modules/websockets/client.py diff --git a/defaults/py_modules/websockets/connection.py b/py_modules/websockets/connection.py similarity index 100% rename from defaults/py_modules/websockets/connection.py rename to py_modules/websockets/connection.py diff --git a/defaults/py_modules/websockets/datastructures.py b/py_modules/websockets/datastructures.py similarity index 100% rename from defaults/py_modules/websockets/datastructures.py rename to py_modules/websockets/datastructures.py diff --git a/defaults/py_modules/websockets/exceptions.py b/py_modules/websockets/exceptions.py similarity index 100% rename from defaults/py_modules/websockets/exceptions.py rename to py_modules/websockets/exceptions.py diff --git a/defaults/py_modules/websockets/extensions/__init__.py b/py_modules/websockets/extensions/__init__.py similarity index 100% rename from defaults/py_modules/websockets/extensions/__init__.py rename to py_modules/websockets/extensions/__init__.py diff --git a/defaults/py_modules/websockets/extensions/base.py b/py_modules/websockets/extensions/base.py similarity index 100% rename from defaults/py_modules/websockets/extensions/base.py rename to py_modules/websockets/extensions/base.py diff --git a/defaults/py_modules/websockets/extensions/permessage_deflate.py b/py_modules/websockets/extensions/permessage_deflate.py similarity index 100% rename from defaults/py_modules/websockets/extensions/permessage_deflate.py rename to py_modules/websockets/extensions/permessage_deflate.py diff --git a/defaults/py_modules/websockets/frames.py b/py_modules/websockets/frames.py similarity index 100% rename from defaults/py_modules/websockets/frames.py rename to py_modules/websockets/frames.py diff --git a/defaults/py_modules/websockets/headers.py b/py_modules/websockets/headers.py similarity index 100% rename from defaults/py_modules/websockets/headers.py rename to py_modules/websockets/headers.py diff --git a/defaults/py_modules/websockets/http.py b/py_modules/websockets/http.py similarity index 100% rename from defaults/py_modules/websockets/http.py rename to py_modules/websockets/http.py diff --git a/defaults/py_modules/websockets/http11.py b/py_modules/websockets/http11.py similarity index 100% rename from defaults/py_modules/websockets/http11.py rename to py_modules/websockets/http11.py diff --git a/defaults/py_modules/websockets/imports.py b/py_modules/websockets/imports.py similarity index 100% rename from defaults/py_modules/websockets/imports.py rename to py_modules/websockets/imports.py diff --git a/defaults/py_modules/websockets/legacy/__init__.py b/py_modules/websockets/legacy/__init__.py similarity index 100% rename from defaults/py_modules/websockets/legacy/__init__.py rename to py_modules/websockets/legacy/__init__.py diff --git a/defaults/py_modules/websockets/legacy/async_timeout.py b/py_modules/websockets/legacy/async_timeout.py similarity index 100% rename from defaults/py_modules/websockets/legacy/async_timeout.py rename to py_modules/websockets/legacy/async_timeout.py diff --git a/defaults/py_modules/websockets/legacy/auth.py b/py_modules/websockets/legacy/auth.py similarity index 100% rename from defaults/py_modules/websockets/legacy/auth.py rename to py_modules/websockets/legacy/auth.py diff --git a/defaults/py_modules/websockets/legacy/client.py b/py_modules/websockets/legacy/client.py similarity index 100% rename from defaults/py_modules/websockets/legacy/client.py rename to py_modules/websockets/legacy/client.py diff --git a/defaults/py_modules/websockets/legacy/compatibility.py b/py_modules/websockets/legacy/compatibility.py similarity index 100% rename from defaults/py_modules/websockets/legacy/compatibility.py rename to py_modules/websockets/legacy/compatibility.py diff --git a/defaults/py_modules/websockets/legacy/framing.py b/py_modules/websockets/legacy/framing.py similarity index 100% rename from defaults/py_modules/websockets/legacy/framing.py rename to py_modules/websockets/legacy/framing.py diff --git a/defaults/py_modules/websockets/legacy/handshake.py b/py_modules/websockets/legacy/handshake.py similarity index 100% rename from defaults/py_modules/websockets/legacy/handshake.py rename to py_modules/websockets/legacy/handshake.py diff --git a/defaults/py_modules/websockets/legacy/http.py b/py_modules/websockets/legacy/http.py similarity index 100% rename from defaults/py_modules/websockets/legacy/http.py rename to py_modules/websockets/legacy/http.py diff --git a/defaults/py_modules/websockets/legacy/protocol.py b/py_modules/websockets/legacy/protocol.py similarity index 100% rename from defaults/py_modules/websockets/legacy/protocol.py rename to py_modules/websockets/legacy/protocol.py diff --git a/defaults/py_modules/websockets/legacy/server.py b/py_modules/websockets/legacy/server.py similarity index 100% rename from defaults/py_modules/websockets/legacy/server.py rename to py_modules/websockets/legacy/server.py diff --git a/defaults/py_modules/websockets/protocol.py b/py_modules/websockets/protocol.py similarity index 100% rename from defaults/py_modules/websockets/protocol.py rename to py_modules/websockets/protocol.py diff --git a/defaults/py_modules/websockets/py.typed b/py_modules/websockets/py.typed similarity index 100% rename from defaults/py_modules/websockets/py.typed rename to py_modules/websockets/py.typed diff --git a/defaults/py_modules/websockets/server.py b/py_modules/websockets/server.py similarity index 100% rename from defaults/py_modules/websockets/server.py rename to py_modules/websockets/server.py diff --git a/defaults/py_modules/websockets/speedups.c b/py_modules/websockets/speedups.c similarity index 100% rename from defaults/py_modules/websockets/speedups.c rename to py_modules/websockets/speedups.c diff --git a/defaults/py_modules/websockets/speedups.pyi b/py_modules/websockets/speedups.pyi similarity index 100% rename from defaults/py_modules/websockets/speedups.pyi rename to py_modules/websockets/speedups.pyi diff --git a/defaults/py_modules/websockets/streams.py b/py_modules/websockets/streams.py similarity index 100% rename from defaults/py_modules/websockets/streams.py rename to py_modules/websockets/streams.py diff --git a/defaults/py_modules/websockets/sync/__init__.py b/py_modules/websockets/sync/__init__.py similarity index 100% rename from defaults/py_modules/websockets/sync/__init__.py rename to py_modules/websockets/sync/__init__.py diff --git a/defaults/py_modules/websockets/sync/client.py b/py_modules/websockets/sync/client.py similarity index 100% rename from defaults/py_modules/websockets/sync/client.py rename to py_modules/websockets/sync/client.py diff --git a/defaults/py_modules/websockets/sync/connection.py b/py_modules/websockets/sync/connection.py similarity index 100% rename from defaults/py_modules/websockets/sync/connection.py rename to py_modules/websockets/sync/connection.py diff --git a/defaults/py_modules/websockets/sync/messages.py b/py_modules/websockets/sync/messages.py similarity index 100% rename from defaults/py_modules/websockets/sync/messages.py rename to py_modules/websockets/sync/messages.py diff --git a/defaults/py_modules/websockets/sync/server.py b/py_modules/websockets/sync/server.py similarity index 100% rename from defaults/py_modules/websockets/sync/server.py rename to py_modules/websockets/sync/server.py diff --git a/defaults/py_modules/websockets/sync/utils.py b/py_modules/websockets/sync/utils.py similarity index 100% rename from defaults/py_modules/websockets/sync/utils.py rename to py_modules/websockets/sync/utils.py diff --git a/defaults/py_modules/websockets/typing.py b/py_modules/websockets/typing.py similarity index 100% rename from defaults/py_modules/websockets/typing.py rename to py_modules/websockets/typing.py diff --git a/defaults/py_modules/websockets/uri.py b/py_modules/websockets/uri.py similarity index 100% rename from defaults/py_modules/websockets/uri.py rename to py_modules/websockets/uri.py diff --git a/defaults/py_modules/websockets/utils.py b/py_modules/websockets/utils.py similarity index 100% rename from defaults/py_modules/websockets/utils.py rename to py_modules/websockets/utils.py diff --git a/defaults/py_modules/websockets/version.py b/py_modules/websockets/version.py similarity index 100% rename from defaults/py_modules/websockets/version.py rename to py_modules/websockets/version.py diff --git a/src/common/components.tsx b/src/common/components.tsx new file mode 100644 index 0000000..ed5af68 --- /dev/null +++ b/src/common/components.tsx @@ -0,0 +1,18 @@ +import { DialogButton } from "decky-frontend-lib"; + +export function IconDialogButton(props: Parameters[0]): ReturnType { + return + {props.children} + +} \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 2b38f9e..1a8c123 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,19 +4,17 @@ import { staticClasses, } from "decky-frontend-lib"; import { FaTerminal } from "react-icons/fa"; - import { registerRoutes, unregisterRoutes } from "./routes"; import SidePanel from "./panel"; import TerminalGlobal from "./common/global"; - export default definePlugin((serverApi: ServerAPI) => { TerminalGlobal.setServer(serverApi); registerRoutes(serverApi.routerHook); return { title:
Decky Terminal
, - content: , + content: , icon: , onDismount() { unregisterRoutes(serverApi.routerHook) diff --git a/src/pages/Terminal.tsx b/src/pages/Terminal.tsx index 0fccb64..8319504 100644 --- a/src/pages/Terminal.tsx +++ b/src/pages/Terminal.tsx @@ -15,7 +15,8 @@ import { AttachAddon } from 'xterm-addon-attach'; import { FitAddon } from 'xterm-addon-fit'; import TerminalGlobal from "../common/global"; import XTermCSS from "../common/xterm_css"; -import { FaExpand, FaKeyboard, FaTerminal } from "react-icons/fa"; +import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaChevronCircleLeft, FaExpand, FaKeyboard, FaTerminal } from "react-icons/fa"; +import { IconDialogButton } from "../common/components"; const Terminal: VFC = () => { @@ -25,6 +26,7 @@ const Terminal: VFC = () => { const [fullScreen, setFullScreen] = useState(false); const [title, setTitle] = useState(null); const [config, setConfig] = useState | null>(null); + const [openFunctionRow, setOpenFunctionRow] = useState(false); let prevId: string|undefined = undefined; // Create a ref to hold the xterm instance @@ -45,7 +47,7 @@ const Terminal: VFC = () => { const getConfig = async (): Promise|undefined> => { const serverAPI = TerminalGlobal.getServer() const config = await serverAPI.callPluginMethod<{}, string[]>("get_config", {}); - console.log('getConfig', config); + if (config.success) { setConfig(config.result) @@ -57,13 +59,12 @@ const Terminal: VFC = () => { const updateTitle = async (title: string): Promise|undefined> => { const serverAPI = TerminalGlobal.getServer() - await serverAPI.callPluginMethod<{ id: string, title: string }, string[]>("set_terminal_title", { id, title }); + await serverAPI.callPluginMethod<{ terminal_id: string, title: string }, string[]>("set_terminal_title", { terminal_id: id, title }); return; } const connectIO = async () => { - console.log('ConnectIO Triggered!'); prevId = id; setTitle(id); @@ -71,7 +72,7 @@ const Terminal: VFC = () => { const serverAPI = TerminalGlobal.getServer() const localConfig = await getConfig() - console.log('config', config, 'localConfig', localConfig); + if (localConfig && xterm) { if (localConfig.__version__ === 1) { if (localConfig.font_family?.trim()) { @@ -84,14 +85,12 @@ const Terminal: VFC = () => { xterm.options.fontSize = fs; } } - - console.log('xterm.options', xterm.options) } } const terminalResult = await serverAPI.callPluginMethod<{ - id: string - }, number>("get_terminal", { id }); + terminal_id: string + }, number>("get_terminal", { terminal_id: id }); if (terminalResult.success) { if (terminalResult.result === null) { xterm?.write("--- Terminal Not Found ---"); @@ -105,8 +104,6 @@ const Terminal: VFC = () => { const result = await serverAPI.callPluginMethod<{}, number>("get_server_port", {}); if (result.success) { - console.log('connectIO', result.result) - const url = new URL('ws://127.0.0.1:'+result.result+'/v1/terminals/'+id); const ws = new WebSocket(url); @@ -141,7 +138,6 @@ const Terminal: VFC = () => { if (xterm) { xterm.onResize((e) => { - console.log('Resize triggered to ', xterm) setWindowSize(e.rows, e.cols); }); @@ -161,19 +157,16 @@ const Terminal: VFC = () => { }; const setWindowSize = async (rows: number, cols: number) => { - console.log('Setting WindowSize to', rows, cols); const serverAPI = TerminalGlobal.getServer() const result = await serverAPI.callPluginMethod<{ - id: string, + terminal_id: string, rows: number, cols: number, }, number>("change_terminal_window_size", { - id, + terminal_id: id, rows, cols, }); - - console.log('setWindowSize', result); } const openKeyboard = () => { @@ -183,7 +176,6 @@ const Terminal: VFC = () => { } const fakeInput = fakeInputRef.current as any - console.log('fakeInput', fakeInput) if (fakeInput?.m_elInput) { fakeInput.m_elInput.click() } else { @@ -203,8 +195,6 @@ const Terminal: VFC = () => { //scrollback: 0, }); xtermRef.current = xterm; - - console.log('xterm configured') wrappedConnectIO() // Clean up function @@ -239,8 +229,6 @@ const Terminal: VFC = () => { if (isFullScreen) xterm.resize(res.cols - colOffset, res.rows - 1) else xterm.resize(res.cols + colOffset, res.rows) } - - console.log('triggered fit!', xtermRef.current?.cols, xtermRef.current?.rows) } } @@ -258,7 +246,6 @@ const Terminal: VFC = () => { const gamepadHandler = (evt: GamepadEvent) => { if (config?.use_dpad) { - console.log('gamepadEvent', evt); evt.preventDefault(); let command: string | undefined = undefined; @@ -311,6 +298,12 @@ const Terminal: VFC = () => { return 'calc('+amount+'em + '+final+'px)'; } + if (!fullScreen) { + if (config?.extra_keys) { + amount += 3; + } + } + return amount+'em'; }; @@ -345,17 +338,53 @@ const Terminal: VFC = () => { { - true && -
- wsRef.current?.send('\x1b[A')}>↑ - wsRef.current?.send('\x1b[B')}>↓ - wsRef.current?.send('\x1b[D')}>← - wsRef.current?.send('\x1b[C')}>→ - - wsRef.current?.send('\x03')}>^C - wsRef.current?.send('\x04')}>^C - wsRef.current?.send('\x1a')}>^Z -
+ (config?.extra_keys && (!fullScreen || config?.handheld_mode)) && + +
+ wsRef.current?.send('\x1b')}>Esc +
+ +
+ { + openFunctionRow && +
+ wsRef.current?.send('\x1b[1P')}>F1 + wsRef.current?.send('\x1b[1Q')}>F2 + wsRef.current?.send('\x1b[1R')}>F3 + wsRef.current?.send('\x1b[1S')}>F4 + wsRef.current?.send('\x1b[15~')}>F5 + wsRef.current?.send('\x1b[17~')}>F6 + wsRef.current?.send('\x1b[18~')}>F7 + wsRef.current?.send('\x1b[19~')}>F8 + wsRef.current?.send('\x1b[20~')}>F9 + wsRef.current?.send('\x1b[21~')}>F10 + wsRef.current?.send('\x1b[23~')}>F11 + wsRef.current?.send('\x1b[24~')}>F12 +
+ } + + { + openFunctionRow ? + setOpenFunctionRow(false)}> : + setOpenFunctionRow(true)}>Fn + + } +
+ +
+ wsRef.current?.send('\x1b[D')}> + wsRef.current?.send('\x1b[A')}> + wsRef.current?.send('\x1b[B')}> + wsRef.current?.send('\x1b[C')}> +
+ +
+ wsRef.current?.send('\x03')}>^C + wsRef.current?.send('\x04')}>^D + wsRef.current?.send('\x12')}>^R + wsRef.current?.send('\x1a')}>^Z +
+
} { diff --git a/src/pages/settings/SettingsPage.tsx b/src/pages/settings/SettingsPage.tsx index 0e8edaa..e102a42 100644 --- a/src/pages/settings/SettingsPage.tsx +++ b/src/pages/settings/SettingsPage.tsx @@ -12,9 +12,7 @@ const SettingsPage: VFC = () => { const getShells = async () => { const serverAPI = TerminalGlobal.getServer() - console.log('getShells triggered') const shells = await serverAPI.callPluginMethod<{}, string[]>("get_shells", {}); - console.log('getShells', shells); if (shells.success) { setShells(shells.result) } else { @@ -25,7 +23,6 @@ const SettingsPage: VFC = () => { const getConfig = async () => { const serverAPI = TerminalGlobal.getServer() const config = await serverAPI.callPluginMethod<{}, string[]>("get_config", {}); - console.log('getConfig', config); if (config.success) { setConfig(config.result) } @@ -92,6 +89,12 @@ const SettingsPage: VFC = () => { }) } + const setExtraKeys = async (enabled: boolean) => { + await appendConfig({ + extra_keys: enabled, + }) + } + const setUseDisplay = async (enabled: boolean) => { await appendConfig({ use_display: enabled, @@ -99,8 +102,6 @@ const SettingsPage: VFC = () => { } useEffect(() => { - console.log('Fetching Settings') - if (!shells || shells.length === 0) getShells(); if (!config) getConfig(); @@ -197,17 +198,35 @@ const SettingsPage: VFC = () => {
-
Use Display
-
Set Display environment variable to allow GUI Applications to run
+
Enable Extra keys
+
Add a row for arrow keys and Ctrl+C,D,Z
{setUseDisplay(e)}} + checked={config?.extra_keys ?? false} + onChange={(e) => {setExtraKeys(e)}} bottomSeparator={"none"} />
+ { + /* + +
+
Use Display
+
Set Display environment variable to allow GUI Applications to run
+
+
+ {setUseDisplay(e)}} + bottomSeparator={"none"} /> +
+
+ */ + } ); }; diff --git a/src/panel.tsx b/src/panel.tsx index 0b6b47a..dad542a 100644 --- a/src/panel.tsx +++ b/src/panel.tsx @@ -16,6 +16,7 @@ import { import { useState, VFC } from "react"; import { FaCog, FaPlus, FaTimesCircle } from "react-icons/fa"; import TerminalGlobal from "./common/global"; +import { IconDialogButton } from "./common/components"; // interface AddMethodArgs { // left: number; @@ -56,7 +57,6 @@ const SidePanel: VFC = ({}) => { "get_terminals", {} ); - console.log('Fetched Terminal', result); if (result.success) { setResult(result.result) @@ -78,12 +78,12 @@ const SidePanel: VFC = ({}) => { } } - const removeTerminal = async (id: string) => { + const removeTerminal = async (terminal_id: string) => { const serverAPI = TerminalGlobal.getServer(); const result = await serverAPI.callPluginMethod<{}, boolean>( "remove_terminal", - { id } + { terminal_id } ); if (result.success) { @@ -106,12 +106,12 @@ const SidePanel: VFC = ({}) => { Add Terminal - { + { Router.CloseSideMenus(); Router.Navigate("/decky-terminal/settings"); }}> - + @@ -135,7 +135,7 @@ const SidePanel: VFC = ({}) => { { terminal.title ?? terminal.id } - { removeTerminal(terminal.id) }} @@ -144,12 +144,11 @@ const SidePanel: VFC = ({}) => { justifyContent: 'center', alignItems: 'center', padding: '5px', - width: '50px', minWidth: 'auto', }} > - + ) diff --git a/src/routes/index.tsx b/src/routes/index.tsx index f269463..e5c82a4 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,7 +1,6 @@ -import { RouterHook, ServerAPI } from "decky-frontend-lib"; +import { RouterHook } from "decky-frontend-lib"; import Settings from "../pages/Settings"; import Terminal from "../pages/Terminal"; -import { VFC } from "react"; export function registerRoutes(routerHook: RouterHook) { routerHook.addRoute('/terminals/:id', Terminal, { @@ -16,4 +15,4 @@ export function registerRoutes(routerHook: RouterHook) { export function unregisterRoutes(routerHook: RouterHook) { routerHook.removeRoute('/terminals/:id'); routerHook.removeRoute('/decky-terminal/settings'); -} \ No newline at end of file +}