From 2eb0fcfa89612e80a588d30f0d63743c2b2e165a Mon Sep 17 00:00:00 2001 From: jakehl Date: Mon, 7 Nov 2022 18:51:03 +0000 Subject: [PATCH] moves projects to tslua --- .gitignore | 2 + package.json | 14 +++ src/helpers.ts | 21 ++++ src/wm.ts | 159 ++++++++++++++++++++++++++++++ tsconfig.json | 15 +++ types/wezterm/actions.d.ts | 9 ++ types/wezterm/coreTypes.d.ts | 183 +++++++++++++++++++++++++++++++++++ types/wezterm/index.d.ts | 3 + types/wezterm/wezterm.d.ts | 46 +++++++++ wezmode.lua | 126 ------------------------ yarn.lock | 89 +++++++++++++++++ 11 files changed, 541 insertions(+), 126 deletions(-) create mode 100644 package.json create mode 100644 src/helpers.ts create mode 100644 src/wm.ts create mode 100644 tsconfig.json create mode 100644 types/wezterm/actions.d.ts create mode 100644 types/wezterm/coreTypes.d.ts create mode 100644 types/wezterm/index.d.ts create mode 100644 types/wezterm/wezterm.d.ts delete mode 100644 wezmode.lua create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index e43b0f9..fd10abd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +node_modules +dist/ diff --git a/package.json b/package.json new file mode 100644 index 0000000..6f690fa --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "wezmode-ts", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts":{ + "build": "tstl --luaBundle wezmode.lua --luaBundleEntry ./src/wm.ts -lt JIT --outDir ./dist/" + }, + "devDependencies": { + "lua-types": "^2.13.0", + "typescript": "^4.8.4", + "typescript-to-lua": "^1.10.1" + } +} diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 0000000..5773dee --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1,21 @@ +type mergable = { [key: string]: mergable | string | number | boolean } + +const isObject = (o: any): o is mergable => { + return typeof o === "object" +} + +export const mergeObjects = ( + o1: T, + o2: P +): T => { + Object.keys(o2).forEach((k) => { + const v1 = o1[k]; + const v2 = o2[k]; + if (isObject(v1) && isObject(v2)) { + o1 = Object.assign(o1, {[k]:mergeObjects(v1, v2)}); + } else { + o1 = Object.assign(o1, {[k]: o2[k]}); + } + }); + return o1; +}; diff --git a/src/wm.ts b/src/wm.ts new file mode 100644 index 0000000..90ade2e --- /dev/null +++ b/src/wm.ts @@ -0,0 +1,159 @@ +import type { Modifier, Key, KeyBind } from "wezterm"; +import * as wezterm from "wezterm"; + +import { mergeObjects } from "./helpers"; + +type describedKeyBind = KeyBind & { + desc: string; +}; + +type mode = { + name: string; + key: Key; + modeColor: string; + keyTable: describedKeyBind[]; + one_shot?: boolean; + until_unknown?: boolean; + prevent_fallback?: boolean; +}; + +type wezmodeOpts = { + modifier: Modifier; + hintSeparator: string; + theme: { + normalModeColor: string; + hintColor: string; + modeTextColor: string; + textColor: string; + }; +}; + +type wezmodeState = { + keys: KeyBind[]; + modeTexts: Record; + keyTables: Record; +}; + +const state: wezmodeState = { + keys: [], + modeTexts: {}, + keyTables: {}, +}; + +const defaultOpts: wezmodeOpts = { + modifier: "CTRL", + hintSeparator: "/", + theme: { + normalModeColor: "red", + hintColor: "green", + modeTextColor: "black", + textColor: "white", + }, +}; + +const createPrefixText = (prefix: string, textColor: string) => { + return wezterm.format([ + { Attribute: { Intensity: "Bold" } }, + { Foreground: { Color: textColor } }, + { Text: prefix }, + ]); +}; + +const createHintText = ( + key: Key, + desc: string, + hintColor: string, + textColor: string +) => { + return wezterm.format([ + { Attribute: { Intensity: "Bold" } }, + { Foreground: { Color: textColor } }, + { Text: "<" }, + { Foreground: { Color: hintColor } }, + { Text: key }, + { Foreground: { Color: textColor } }, + { Text: `> ${desc}` }, + ]); +}; + +const createModeText = (name: string, textColor: string, modeColor: string) => { + return wezterm.format([ + { Attribute: { Intensity: "Bold" } }, + { Foreground: { Color: textColor } }, + { Background: { Color: modeColor } }, + { Text: ` ${name.toUpperCase()} MODE ` }, + ]); +}; + +const setup = (modes: mode[], opts?: Partial) => { + const options = mergeObjects(defaultOpts, opts ?? {}); + + const modeHints = modes + .map((m) => + createHintText( + m.key, + m.name, + options.theme.hintColor, + options.theme.textColor + ) + ) + .join(` ${options.hintSeparator} `); + + state.modeTexts["normal"] = `${createPrefixText( + options.modifier, + options.theme.normalModeColor + )} + ${modeHints} ${createModeText("normal", options.theme.modeTextColor, options.theme.normalModeColor)}`; + + modes.forEach((m) => { + state.keys.push({ + key: m.key, + mods: options.modifier, + action: wezterm.action.ActivateKeyTable({ + name: m.name, + one_shot: !!m.one_shot, + until_unknown: !!m.until_unknown, + prevent_fallback: !!m.prevent_fallback, + }), + }); + + state.keyTables[m.name] = m.keyTable; + + const actionHints = m.keyTable + .map((k) => + createHintText( + k.key, + k.desc, + options.theme.hintColor, + options.theme.textColor + ) + ) + .join(` ${options.hintSeparator} `); + + state.modeTexts[m.name] = `${actionHints} ${createModeText( + m.name, + options.theme.modeTextColor, + m.modeColor + )}`; + }); +}; + +const getModeText = (modeName: string) => state.modeTexts[modeName]; +const getKeys = () => state.keys; +const getKeyTables = () => state.keyTables; +const handleRightStatusUpdate = () => { + wezterm.on("update-right-status", (window) => { + window.set_right_status(getModeText(window.active_key_table() ?? "normal")); + }); +}; +const mergeTables = mergeObjects; +const extendTable = (t1: any[], t2: any[]) => t1.concat(t2); + +export { + setup, + getModeText, + getKeys, + getKeyTables, + handleRightStatusUpdate, + mergeTables, + extendTable, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..cbb7005 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "include": ["./src"], + "compilerOptions": { + "target": "esnext", + "lib": ["esnext"], + "moduleResolution": "node", + "types": [], + "strict": true, + "types": ["lua-types/jit", "./types/wezterm"], + }, + "tstl": { + "luaTarget": "JIT", + "noImplicitSelf": true + } +} diff --git a/types/wezterm/actions.d.ts b/types/wezterm/actions.d.ts new file mode 100644 index 0000000..abd5845 --- /dev/null +++ b/types/wezterm/actions.d.ts @@ -0,0 +1,9 @@ +declare module "wezterm/coreTypes/actionFuncs" { + export type Action = () => void; + export type ActivateKeyTable = (opts: { + name: string, + one_shot: boolean, + until_unknown: boolean, + prevent_fallback: boolean + }) => Action; +} diff --git a/types/wezterm/coreTypes.d.ts b/types/wezterm/coreTypes.d.ts new file mode 100644 index 0000000..b796c82 --- /dev/null +++ b/types/wezterm/coreTypes.d.ts @@ -0,0 +1,183 @@ +declare module "wezterm/coreTypes" { + // ** helpers + type uniqueUnion< + baseUnion extends string, + removalCandidates extends string, + usedCandidate + > = Exclude>; + + type uniqueSet = uniqueUnion< + modifierKeys, + superKeys, + s + > & + uniqueUnion; + + type modifierPermutations< + t extends string, + u extends string = t + > = t extends any ? t | `${t}|${modifierPermutations>}` : never; + + export type formatAttributeUnderline = + | "None" + | "Single" + | "Double" + | "Curly" + | "Dotted" + | "Dashed"; + + export type formatAttributeIntensity = "Normal" | "Bold" | "Half"; + + export type formatAttributeElement = { + Attribute: + | { Underline: formatAttributeUnderline } + | { Intensity: formatAttributeIntensity } + | { Italic: boolean }; + }; + + export type formatColor = { Color: string } | { AnsiColor: string }; + export type formatForegroundElement = { Foreground: formatColor }; + export type formatBackgroundElement = { Background: formatColor }; + export type formatTextElement = { Text: string } + + export type formatElement = + | formatAttributeElement + | formatForegroundElement + | formatBackgroundElement + | formatTextElement; + + export type keyMapPreference = "Physical" | "Mapped"; + + export type modifierKeys = + | "SUPER" + | "CMD" + | "WIN" + | "CTRL" + | "SHIFT" + | "ALT" + | "OPT" + | "META" + | "LEADER" + | "VoidSymbol"; + + export type mappedKeys = `mapped:${allKeys}`; + export type physicalKeys = `phys:${allKeys}`; + export type allKeys = + | "Hyper" + | "Super" + | "Meta" + | "Cancel" + | "Backspace" + | "Tab" + | "Clear" + | "Enter" + | "Shift" + | "Escape" + | "LeftShift" + | "RightShift" + | "Control" + | "LeftControl" + | "RightControl" + | "Alt" + | "LeftAlt" + | "RightAlt" + | "Menu" + | "LeftMenu" + | "RightMenu" + | "Pause" + | "CapsLock" + | "VoidSymbol" + | "PageUp" + | "PageDown" + | "End" + | "Home" + | "LeftArrow" + | "RightArrow" + | "UpArrow" + | "DownArrow" + | "Select" + | "Print" + | "Execute" + | "PrintScreen" + | "Insert" + | "Delete" + | "Help" + | "LeftWindows" + | "RightWindows" + | "Applications" + | "Sleep" + | "Numpad0" + | "Numpad1" + | "Numpad2" + | "Numpad3" + | "Numpad4" + | "Numpad5" + | "Numpad6" + | "Numpad7" + | "Numpad8" + | "Numpad9" + | "Multiply" + | "Add" + | "Separator" + | "Subtract" + | "Decimal" + | "Divide" + | "NumLock" + | "ScrollLock" + | "BrowserBack" + | "BrowserForward" + | "BrowserRefresh" + | "BrowserStop" + | "BrowserSearch" + | "BrowserFavorites" + | "BrowserHome" + | "VolumeMute" + | "VolumeDown" + | "VolumeUp" + | "MediaNextTrack" + | "MediaPrevTrack" + | "MediaStop" + | "MediaPlayPause" + | "ApplicationLeftArrow" + | "ApplicationRightArrow" + | "ApplicationUpArrow" + | "ApplicationDownArrow" + | "F1" + | "F2" + | "F3" + | "F4" + | "F5" + | "F6" + | "F7" + | "F8" + | "F9" + | "F10" + | "F11" + | "F12" + | "F13" + | "F14" + | "F15" + | "F16" + | "F17" + | "F18" + | "F19" + | "F20" + | "F21" + | "F22" + | "F23" + | "F24"; + + export type superKeys = "SUPER" | "WIN" | "CMD"; + export type metaKeys = "ALT" | "OPT" | "META"; + + export type modifierCombos = // there has to be a nicer way than this?? + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations> + | modifierPermutations>; +} diff --git a/types/wezterm/index.d.ts b/types/wezterm/index.d.ts new file mode 100644 index 0000000..90cf043 --- /dev/null +++ b/types/wezterm/index.d.ts @@ -0,0 +1,3 @@ +/// +/// +/// diff --git a/types/wezterm/wezterm.d.ts b/types/wezterm/wezterm.d.ts new file mode 100644 index 0000000..8251e31 --- /dev/null +++ b/types/wezterm/wezterm.d.ts @@ -0,0 +1,46 @@ +/** @noResolution **/ +declare module "wezterm" { + import type { + allKeys, + mappedKeys, + physicalKeys, + modifierCombos, + formatElement, + } from "wezterm/coreTypes"; + + import type * as actions from "wezterm/coreTypes/actionFuncs"; + + export class Window { + set_right_status(text: string): void; + active_key_table(): string; + } + + export type Modifier = modifierCombos; + export type Key = allKeys | mappedKeys | physicalKeys; + + export type KeyBind = { + key: Key; + mods?: Modifier; + action: actions.Action; + }; + + export type KeyTable = KeyBind[]; + + export type FormatElement = formatElement; + + export const action: { + ActivateKeyTable: actions.ActivateKeyTable; + }; + + /** @noSelf **/ + export const format: (elements: formatElement[]) => string; + + /** @noSelf **/ + type eventHandler = (window: Window, pane: any) => void; + + /** @noSelf **/ + export const on: ( + event: string, + handler: eventHandler + ) => void; +} diff --git a/wezmode.lua b/wezmode.lua deleted file mode 100644 index 4da72cd..0000000 --- a/wezmode.lua +++ /dev/null @@ -1,126 +0,0 @@ -local wezterm = require("wezterm") - --- local state -local state = { - keys = {}, - modeTexts = {}, - keyTables = {} -} - --- exported state -local wezmode = {} - -wezmode.getModeText = function(modeName) - return state.modeTexts[modeName] or "" -end - -wezmode.defaultOpts = { - modifier = "CTRL", - manualMode = false, - hintSeparator = "/", - normalModeColor = "red", - hintColor = "green", - modeTextColor = "black", - textColor = "white", -} - -wezmode.getKeys = function() return state.keys end - -wezmode.getKeyTables = function() return state.keyTables end - -wezmode.handleRightStatusUpdate = function() - wezterm.on('update-right-status', function(window) - window:set_right_status(wezmode.getModeText(window:active_key_table() or "normal")) - end) -end - -wezmode.mergeTables = function(t1, t2) - for k, v in pairs(t2) do - if (type(v) == "table") and (type(t1[k] or false) == "table") then - wezmode.mergeTables(t1[k], t2[k]) - else - t1[k] = v - end - end - return t1 -end - -wezmode.extendTable = function(t1, t2) - for _, v in pairs(t2) do - table.insert(t1, v) - end - return t1 -end - -local createPrefixText = function(modifier, color) - return wezterm.format({ - { Attribute = { Intensity = "Bold" } }, - { Foreground = { Color = color } }, - { Text = modifier } - }) -end - -local createHintText = function(key, desc, hintColor, textColor) - local element = { - { Attribute = { Intensity = "Bold" } }, - { Foreground = { Color = textColor } }, - { Text = "<" }, - { Foreground = { Color = hintColor } }, - { Text = key }, - { Foreground = { Color = textColor } }, - { Text = "> " .. desc }, - } - return wezterm.format(element) -end - -local createModeText = function(name, foreground, background) - local element = { - { Attribute = { Intensity = "Bold" } }, - { Foreground = { Color = foreground } }, - { Background = { Color = background } }, - { Text = " " .. string.upper(name) .. " " .. "MODE " }, - } - return " " .. wezterm.format(element) -end - - -wezmode.setup = function(modes, opts) - opts = wezmode.mergeTables(wezmode.defaultOpts, opts or {}) - - -- normal mode text setup - local normalModePrefix = createPrefixText(opts.modifier, opts.normalModeColor) .. " + " - local hints = {} - - for _, v in pairs(modes) do - -- create the hints for normal mode - table.insert(hints, createHintText(v.key, v.name, opts.hintColor, opts.textColor)) - - -- create the initial keybinds - table.insert(state.keys, { - key = v.key, - mods = opts.modifier, - action = wezterm.action.ActivateKeyTable({ - name = v.name, - one_shot = v.one_shot or false, - until_unknown = v.until_unknown or true, - }) - }) - - -- create the key tables - state.keyTables[v.name] = v.keyTable; - local modeHints = {} - for _, ktv in pairs(v.keyTable) do - table.insert(modeHints, createHintText(ktv.key, ktv.desc, opts.hintColor, opts.textColor)) - end - state.modeTexts[v.name] = table.concat(modeHints, " " .. opts.hintSeparator .. " ") .. - " " .. createModeText(v.name, opts.modeTextColor, v.modeColor) - end - - -- tie up the text for normal mode - state.modeTexts["normal"] = - normalModePrefix .. - table.concat(hints, " " .. opts.hintSeparator .. " ") - .. " " .. createModeText("normal", opts.modeTextColor, opts.normalModeColor) -end - -return wezmode; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..daf5c4c --- /dev/null +++ b/yarn.lock @@ -0,0 +1,89 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@typescript-to-lua/language-extensions@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@typescript-to-lua/language-extensions/-/language-extensions-1.0.0.tgz#fad73b01c21ace67abbd1477cd2b1f8b3ce7287b" + integrity sha512-GtmhFqyg+txpGgGLM3mlS3R6AEG9MQhKALxxcbr6SBzg9u7YAXcPKqUBaBYd6nH+Pi/eQLcWz4BNOLhz8v4TjQ== + +enhanced-resolve@^5.8.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" + integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +graceful-fs@^4.2.4: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +lua-types@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/lua-types/-/lua-types-2.13.0.tgz#b76b2d56cfba7e649fb57498f1e60cec4accdb8c" + integrity sha512-wra+mIPZlcbm8bYoM6QutEwTOAjZ9KyKMiaidGeZ+QJItIAK9hwG+1I6GCDKnW0T9E/Xv2IoTFtZwxQv4zAIJw== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +resolve@^1.15.1: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +typescript-to-lua@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/typescript-to-lua/-/typescript-to-lua-1.10.1.tgz#0046d88237dcc013e69441df1734d881168a32bf" + integrity sha512-R6KQc1YzFcejyaZ9tAvVK0MFTlRS1b10vON5sxjtGVSUWl+W4KRLik0LDCgKfI0wnDQH+LNVnKBNUsBfTtEoQQ== + dependencies: + "@typescript-to-lua/language-extensions" "1.0.0" + enhanced-resolve "^5.8.2" + resolve "^1.15.1" + source-map "^0.7.3" + +typescript@^4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==