termcast 1.3.54 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action-utils.d.ts.map +1 -1
- package/dist/action-utils.js +17 -132
- package/dist/action-utils.js.map +1 -1
- package/dist/apis/cache.d.ts +8 -30
- package/dist/apis/cache.d.ts.map +1 -1
- package/dist/apis/cache.js +9 -271
- package/dist/apis/cache.js.map +1 -1
- package/dist/apis/clipboard.d.ts +4 -2
- package/dist/apis/clipboard.d.ts.map +1 -1
- package/dist/apis/clipboard.js +18 -31
- package/dist/apis/clipboard.js.map +1 -1
- package/dist/apis/environment.d.ts.map +1 -1
- package/dist/apis/environment.js +14 -49
- package/dist/apis/environment.js.map +1 -1
- package/dist/apis/localstorage.d.ts +7 -12
- package/dist/apis/localstorage.d.ts.map +1 -1
- package/dist/apis/localstorage.js +7 -184
- package/dist/apis/localstorage.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +16 -15
- package/dist/app.js.map +1 -1
- package/dist/cli.js +7 -6
- package/dist/cli.js.map +1 -1
- package/dist/components/actions.d.ts.map +1 -1
- package/dist/components/actions.js +13 -2
- package/dist/components/actions.js.map +1 -1
- package/dist/components/extension-preferences.d.ts.map +1 -1
- package/dist/components/extension-preferences.js +7 -8
- package/dist/components/extension-preferences.js.map +1 -1
- package/dist/components/form/file-autocomplete.js +2 -2
- package/dist/components/form/file-autocomplete.js.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +242 -14
- package/dist/components/list.js.map +1 -1
- package/dist/e2e-node.d.ts.map +1 -1
- package/dist/e2e-node.js +5 -4
- package/dist/e2e-node.js.map +1 -1
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +5 -2
- package/dist/extensions/dev.js.map +1 -1
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +2 -1
- package/dist/globals.js.map +1 -1
- package/dist/internal/error-handler.d.ts.map +1 -1
- package/dist/internal/error-handler.js +21 -19
- package/dist/internal/error-handler.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +41 -1
- package/dist/internal/providers.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +31 -29
- package/dist/logger.js.map +1 -1
- package/dist/platform/browser/cache.d.ts +41 -0
- package/dist/platform/browser/cache.d.ts.map +1 -0
- package/dist/platform/browser/cache.js +262 -0
- package/dist/platform/browser/cache.js.map +1 -0
- package/dist/platform/browser/localstorage.d.ts +20 -0
- package/dist/platform/browser/localstorage.d.ts.map +1 -0
- package/dist/platform/browser/localstorage.js +102 -0
- package/dist/platform/browser/localstorage.js.map +1 -0
- package/dist/platform/browser/runtime.d.ts +51 -0
- package/dist/platform/browser/runtime.d.ts.map +1 -0
- package/dist/platform/browser/runtime.js +164 -0
- package/dist/platform/browser/runtime.js.map +1 -0
- package/dist/platform/bun/sqlite.d.ts +17 -0
- package/dist/platform/bun/sqlite.d.ts.map +1 -0
- package/dist/platform/bun/sqlite.js +6 -0
- package/dist/platform/bun/sqlite.js.map +1 -0
- package/dist/platform/node/cache.d.ts +35 -0
- package/dist/platform/node/cache.d.ts.map +1 -0
- package/dist/platform/node/cache.js +269 -0
- package/dist/platform/node/cache.js.map +1 -0
- package/dist/platform/node/localstorage.d.ts +17 -0
- package/dist/platform/node/localstorage.d.ts.map +1 -0
- package/dist/platform/node/localstorage.js +186 -0
- package/dist/platform/node/localstorage.js.map +1 -0
- package/dist/platform/node/runtime.d.ts +52 -0
- package/dist/platform/node/runtime.d.ts.map +1 -0
- package/dist/platform/node/runtime.js +230 -0
- package/dist/platform/node/runtime.js.map +1 -0
- package/dist/platform/node/sqlite.d.ts +27 -0
- package/dist/platform/node/sqlite.d.ts.map +1 -0
- package/dist/platform/node/sqlite.js +21 -0
- package/dist/platform/node/sqlite.js.map +1 -0
- package/dist/state.d.ts +5 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +6 -28
- package/dist/state.js.map +1 -1
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +17 -22
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +42 -47
- package/dist/utils.js.map +1 -1
- package/dist/vim-mode.d.ts +40 -0
- package/dist/vim-mode.d.ts.map +1 -0
- package/dist/vim-mode.js +135 -0
- package/dist/vim-mode.js.map +1 -0
- package/fonts/Inconsolata.otf +0 -0
- package/fonts/SIL Open Font License.txt +41 -0
- package/package.json +60 -8
- package/src/action-utils.tsx +27 -124
- package/src/apis/cache.test.ts +1 -1
- package/src/apis/cache.tsx +9 -373
- package/src/apis/clipboard.tsx +29 -38
- package/src/apis/environment.tsx +25 -52
- package/src/apis/localstorage.tsx +8 -214
- package/src/app.tsx +16 -15
- package/src/cli.tsx +14 -15
- package/src/compile.vitest.tsx +2 -2
- package/src/components/actions.tsx +19 -1
- package/src/components/extension-preferences.tsx +7 -8
- package/src/components/form/file-autocomplete.tsx +2 -2
- package/src/components/list.tsx +279 -14
- package/src/e2e-node.tsx +7 -7
- package/src/examples/action-shortcut.vitest.tsx +2 -2
- package/src/examples/actions-context.vitest.tsx +1 -1
- package/src/examples/bar-graph-weekly.vitest.tsx +10 -36
- package/src/examples/detail-metadata-showcase.vitest.tsx +36 -36
- package/src/examples/form-basic.vitest.tsx +21 -17
- package/src/examples/github.vitest.tsx +4 -4
- package/src/examples/graph-bar-chart.vitest.tsx +13 -11
- package/src/examples/graph-polymarket.vitest.tsx +2 -2
- package/src/examples/graph-row.vitest.tsx +66 -66
- package/src/examples/graph-styles.vitest.tsx +12 -12
- package/src/examples/internal/simple-scrollbox.vitest.tsx +14 -48
- package/src/examples/list-detail-metadata.vitest.tsx +5 -5
- package/src/examples/list-fetch-data.vitest.tsx +3 -3
- package/src/examples/list-item-accessories.vitest.tsx +2 -2
- package/src/examples/list-loading-empty-view.vitest.tsx +1 -1
- package/src/examples/list-no-actions.vitest.tsx +2 -2
- package/src/examples/list-scrollbox.vitest.tsx +5 -5
- package/src/examples/list-spacing-mode.vitest.tsx +3 -3
- package/src/examples/list-with-detail.vitest.tsx +68 -68
- package/src/examples/list-with-dropdown.vitest.tsx +5 -5
- package/src/examples/list-with-sections.vitest.tsx +27 -27
- package/src/examples/simple-candle-chart.vitest.tsx +7 -7
- package/src/examples/simple-detail-markdown.vitest.tsx +8 -8
- package/src/examples/simple-detail-table.vitest.tsx +8 -8
- package/src/examples/simple-graph.vitest.tsx +3 -3
- package/src/examples/simple-grid.vitest.tsx +14 -14
- package/src/examples/simple-heatmap.vitest.tsx +1 -1
- package/src/examples/simple-navigation.vitest.tsx +17 -17
- package/src/examples/simple-progress-bar.vitest.tsx +1 -1
- package/src/examples/store.vitest.tsx +1 -1
- package/src/examples/swift-extension.vitest.tsx +2 -2
- package/src/examples/table-edge-cases.vitest.tsx +18 -18
- package/src/examples/toast-action.vitest.tsx +2 -2
- package/src/extensions/dev.tsx +5 -2
- package/src/extensions/dev.vitest.tsx +3 -3
- package/src/globals.ts +2 -1
- package/src/internal/error-handler.tsx +19 -21
- package/src/internal/providers.tsx +39 -0
- package/src/logger.tsx +38 -41
- package/src/platform/browser/cache.ts +327 -0
- package/src/platform/browser/localstorage.ts +119 -0
- package/src/platform/browser/runtime.ts +209 -0
- package/src/platform/bun/sqlite.ts +19 -0
- package/src/platform/node/cache.ts +372 -0
- package/src/platform/node/localstorage.ts +214 -0
- package/src/platform/node/runtime.ts +264 -0
- package/src/platform/node/sqlite.ts +43 -0
- package/src/state.tsx +17 -28
- package/src/utils/file-system.ts +17 -22
- package/src/utils.test.tsx +1 -1
- package/src/utils.tsx +56 -47
- package/src/vim-mode.tsx +153 -0
- package/src/apis/sqlite.ts +0 -14
|
@@ -1,214 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function getCurrentDatabasePath(): string {
|
|
11
|
-
const { extensionPath } = useStore.getState()
|
|
12
|
-
|
|
13
|
-
if (!extensionPath) {
|
|
14
|
-
throw new Error('Cannot access LocalStorage - extensionPath not set')
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return path.join(extensionPath, '.termcast-bundle', 'data.db')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getDatabase(): Database {
|
|
21
|
-
const dbPath = getCurrentDatabasePath()
|
|
22
|
-
|
|
23
|
-
// Check if we need to reconnect due to path change
|
|
24
|
-
if (db && currentDbPath !== dbPath) {
|
|
25
|
-
db.close()
|
|
26
|
-
db = null
|
|
27
|
-
currentDbPath = null
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!db) {
|
|
31
|
-
// Ensure parent directory exists
|
|
32
|
-
const dbDir = path.dirname(dbPath)
|
|
33
|
-
if (!fs.existsSync(dbDir)) {
|
|
34
|
-
fs.mkdirSync(dbDir, { recursive: true })
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
db = new Database(dbPath, {
|
|
38
|
-
create: true,
|
|
39
|
-
readwrite: true,
|
|
40
|
-
})
|
|
41
|
-
currentDbPath = dbPath
|
|
42
|
-
|
|
43
|
-
// Use WAL mode and optimize for single file usage
|
|
44
|
-
db.exec('PRAGMA journal_mode = WAL')
|
|
45
|
-
db.exec('PRAGMA wal_autocheckpoint = 1000')
|
|
46
|
-
db.exec('PRAGMA synchronous = NORMAL')
|
|
47
|
-
|
|
48
|
-
db.exec(`
|
|
49
|
-
CREATE TABLE IF NOT EXISTS localstorage (
|
|
50
|
-
key TEXT PRIMARY KEY,
|
|
51
|
-
value TEXT NOT NULL,
|
|
52
|
-
type TEXT NOT NULL
|
|
53
|
-
)
|
|
54
|
-
`)
|
|
55
|
-
}
|
|
56
|
-
return db
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
export namespace LocalStorage {
|
|
62
|
-
export type Value = string | number | boolean
|
|
63
|
-
|
|
64
|
-
export interface Values {
|
|
65
|
-
[key: string]: any
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function getItem<T extends Value = Value>(
|
|
69
|
-
key: string,
|
|
70
|
-
): Promise<T | undefined> {
|
|
71
|
-
return new Promise((resolve) => {
|
|
72
|
-
try {
|
|
73
|
-
const db = getDatabase()
|
|
74
|
-
const row = db
|
|
75
|
-
.prepare('SELECT value, type FROM localstorage WHERE key = ?')
|
|
76
|
-
.get(key) as { value: string; type: string } | undefined
|
|
77
|
-
|
|
78
|
-
if (!row) {
|
|
79
|
-
resolve(undefined)
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let value: Value
|
|
84
|
-
switch (row.type) {
|
|
85
|
-
case 'number':
|
|
86
|
-
value = parseFloat(row.value)
|
|
87
|
-
break
|
|
88
|
-
case 'boolean':
|
|
89
|
-
value = row.value === 'true'
|
|
90
|
-
break
|
|
91
|
-
default:
|
|
92
|
-
value = row.value
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
resolve(value as T)
|
|
96
|
-
} catch (err) {
|
|
97
|
-
logger.error('LocalStorage.getItem error:', err)
|
|
98
|
-
resolve(undefined)
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function getItemSync<T extends Value = Value>(
|
|
104
|
-
key: string,
|
|
105
|
-
): T | undefined {
|
|
106
|
-
try {
|
|
107
|
-
const db = getDatabase()
|
|
108
|
-
const row = db
|
|
109
|
-
.prepare('SELECT value, type FROM localstorage WHERE key = ?')
|
|
110
|
-
.get(key) as { value: string; type: string } | undefined
|
|
111
|
-
|
|
112
|
-
if (!row) {
|
|
113
|
-
return undefined
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
let value: Value
|
|
117
|
-
switch (row.type) {
|
|
118
|
-
case 'number':
|
|
119
|
-
value = parseFloat(row.value)
|
|
120
|
-
break
|
|
121
|
-
case 'boolean':
|
|
122
|
-
value = row.value === 'true'
|
|
123
|
-
break
|
|
124
|
-
default:
|
|
125
|
-
value = row.value
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return value as T
|
|
129
|
-
} catch (err) {
|
|
130
|
-
logger.error('LocalStorage.getItemSync error:', err)
|
|
131
|
-
return undefined
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export async function setItem(key: string, value: Value): Promise<void> {
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
try {
|
|
138
|
-
const db = getDatabase()
|
|
139
|
-
const type = typeof value
|
|
140
|
-
const stringValue = String(value)
|
|
141
|
-
|
|
142
|
-
db.prepare(
|
|
143
|
-
'INSERT OR REPLACE INTO localstorage (key, value, type) VALUES (?, ?, ?)',
|
|
144
|
-
).run(key, stringValue, type)
|
|
145
|
-
resolve()
|
|
146
|
-
} catch (err) {
|
|
147
|
-
logger.error('LocalStorage.setItem error:', err)
|
|
148
|
-
reject(err)
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export async function removeItem(key: string): Promise<void> {
|
|
154
|
-
return new Promise((resolve, reject) => {
|
|
155
|
-
try {
|
|
156
|
-
const db = getDatabase()
|
|
157
|
-
db.prepare('DELETE FROM localstorage WHERE key = ?').run(key)
|
|
158
|
-
resolve()
|
|
159
|
-
} catch (err) {
|
|
160
|
-
logger.error('LocalStorage.removeItem error:', err)
|
|
161
|
-
reject(err)
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export async function allItems<T extends Values = Values>(): Promise<T> {
|
|
167
|
-
return new Promise((resolve, reject) => {
|
|
168
|
-
try {
|
|
169
|
-
const db = getDatabase()
|
|
170
|
-
const rows = db
|
|
171
|
-
.prepare('SELECT key, value, type FROM localstorage')
|
|
172
|
-
.all() as Array<{
|
|
173
|
-
key: string
|
|
174
|
-
value: string
|
|
175
|
-
type: string
|
|
176
|
-
}>
|
|
177
|
-
|
|
178
|
-
const result: Values = {}
|
|
179
|
-
for (const row of rows) {
|
|
180
|
-
let value: Value
|
|
181
|
-
switch (row.type) {
|
|
182
|
-
case 'number':
|
|
183
|
-
value = parseFloat(row.value)
|
|
184
|
-
break
|
|
185
|
-
case 'boolean':
|
|
186
|
-
value = row.value === 'true'
|
|
187
|
-
break
|
|
188
|
-
default:
|
|
189
|
-
value = row.value
|
|
190
|
-
}
|
|
191
|
-
result[row.key] = value
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
resolve(result as T)
|
|
195
|
-
} catch (err) {
|
|
196
|
-
logger.error('LocalStorage.allItems error:', err)
|
|
197
|
-
reject(err)
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export async function clear(): Promise<void> {
|
|
203
|
-
return new Promise((resolve, reject) => {
|
|
204
|
-
try {
|
|
205
|
-
const db = getDatabase()
|
|
206
|
-
db.exec('DELETE FROM localstorage')
|
|
207
|
-
resolve()
|
|
208
|
-
} catch (err) {
|
|
209
|
-
logger.error('LocalStorage.clear error:', err)
|
|
210
|
-
reject(err)
|
|
211
|
-
}
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* LocalStorage API — platform-agnostic facade.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the platform-specific LocalStorage from #platform/localstorage
|
|
5
|
+
* (SQLite on Node/Bun, window.localStorage on browser).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { LocalStorage } from '#platform/localstorage'
|
package/src/app.tsx
CHANGED
|
@@ -494,11 +494,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|
|
494
494
|
if (dir[i] == L'\\\\') { dir[i + 1] = L'\\0'; break; }
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
/* Set TERMCAST_WEZTERM_CONFIG env var so the TUI can rewrite the config on theme change */
|
|
498
|
-
WCHAR configPath[MAX_PATH * 2];
|
|
499
|
-
wsprintfW(configPath, L"%sruntime\\\\config\\\\wezterm.lua", dir);
|
|
500
|
-
SetEnvironmentVariableW(L"TERMCAST_WEZTERM_CONFIG", configPath);
|
|
501
|
-
|
|
502
497
|
/* Set default theme name baked at build time */
|
|
503
498
|
SetEnvironmentVariableW(L"TERMCAST_DEFAULT_THEME", L"${themeName}");
|
|
504
499
|
|
|
@@ -618,6 +613,8 @@ config.keys = {
|
|
|
618
613
|
{ key = 'RightArrow', mods = 'SUPER', action = wezterm.action.SendString('\\x1b[1;9C') },
|
|
619
614
|
{ key = 'UpArrow', mods = 'SUPER', action = wezterm.action.SendString('\\x1b[1;9A') },
|
|
620
615
|
{ key = 'DownArrow', mods = 'SUPER', action = wezterm.action.SendString('\\x1b[1;9B') },
|
|
616
|
+
-- Cmd+Backspace -> delete to line start (backspace codepoint = 127, super modifier = 9)
|
|
617
|
+
{ key = 'Backspace', mods = 'SUPER', action = wezterm.action.SendString('\\x1b[127;9u') },
|
|
621
618
|
}
|
|
622
619
|
`
|
|
623
620
|
: ''
|
|
@@ -637,9 +634,9 @@ config.window_decorations = '${platform === 'darwin' ? 'TITLE|RESIZE' : 'RESIZE'
|
|
|
637
634
|
config.window_padding = { left = 0, right = 0, top = 0, bottom = 0 }
|
|
638
635
|
config.window_close_confirmation = 'NeverPrompt'
|
|
639
636
|
|
|
640
|
-
-- Background color
|
|
641
|
-
--
|
|
642
|
-
--
|
|
637
|
+
-- Background color: the TUI sets this dynamically via OSC 11 escape sequence
|
|
638
|
+
-- on startup and every theme change, so the window edges/padding always match.
|
|
639
|
+
-- This initial value comes from the theme configured at build time.
|
|
643
640
|
config.colors = { background = '${backgroundColor}' }
|
|
644
641
|
|
|
645
642
|
-- Default window size: 120x36 is comfortable for TUI apps (WezTerm default is 80x24)
|
|
@@ -681,10 +678,9 @@ function generateLaunchScript({ weztermBinaryName, themeName }: { weztermBinaryN
|
|
|
681
678
|
return `\
|
|
682
679
|
#!/bin/bash
|
|
683
680
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
684
|
-
export TERMCAST_WEZTERM_CONFIG="$DIR/../Resources/wezterm.lua"
|
|
685
681
|
export TERMCAST_DEFAULT_THEME="${themeName}"
|
|
686
682
|
export TERMCAST_APP_MODE=1
|
|
687
|
-
exec "$DIR/${weztermBinaryName}" --config-file "$
|
|
683
|
+
exec "$DIR/${weztermBinaryName}" --config-file "$DIR/../Resources/wezterm.lua"
|
|
688
684
|
`
|
|
689
685
|
}
|
|
690
686
|
|
|
@@ -694,10 +690,9 @@ function generateLinuxLaunchScript({ themeName }: { themeName: string }): string
|
|
|
694
690
|
return `\
|
|
695
691
|
#!/bin/bash
|
|
696
692
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
697
|
-
export TERMCAST_WEZTERM_CONFIG="$DIR/runtime/config/wezterm.lua"
|
|
698
693
|
export TERMCAST_DEFAULT_THEME="${themeName}"
|
|
699
694
|
export TERMCAST_APP_MODE=1
|
|
700
|
-
exec "$DIR/runtime/wezterm-gui" --config-file "$
|
|
695
|
+
exec "$DIR/runtime/wezterm-gui" --config-file "$DIR/runtime/config/wezterm.lua"
|
|
701
696
|
`
|
|
702
697
|
}
|
|
703
698
|
|
|
@@ -1121,8 +1116,9 @@ async function resolveBuildContext({
|
|
|
1121
1116
|
// because PowerShell splits unquoted paths on whitespace.
|
|
1122
1117
|
const safeName = appName.replace(/[/\\\s]+/g, '-').replace(/^-+|-+$/g, '')
|
|
1123
1118
|
|
|
1124
|
-
// Resolve font directory: --font-dir flag,
|
|
1125
|
-
//
|
|
1119
|
+
// Resolve font directory: --font-dir flag, fonts/ in extension root, or termcast's
|
|
1120
|
+
// built-in fonts/ as fallback. The built-in Inconsolata font ships with termcast so
|
|
1121
|
+
// every app has a guaranteed monospace font without depending on system fonts.
|
|
1126
1122
|
const fontDirPath = (() => {
|
|
1127
1123
|
if (fontDir) {
|
|
1128
1124
|
const resolved = path.isAbsolute(fontDir)
|
|
@@ -1141,11 +1137,16 @@ async function resolveBuildContext({
|
|
|
1141
1137
|
if (fs.existsSync(defaultFontDir) && fs.statSync(defaultFontDir).isDirectory()) {
|
|
1142
1138
|
return defaultFontDir
|
|
1143
1139
|
}
|
|
1140
|
+
// Fall back to termcast's built-in fonts/ directory (contains Inconsolata)
|
|
1141
|
+
const builtinFontDir = path.join(__dirname, '..', 'fonts')
|
|
1142
|
+
if (fs.existsSync(builtinFontDir) && fs.statSync(builtinFontDir).isDirectory()) {
|
|
1143
|
+
return builtinFontDir
|
|
1144
|
+
}
|
|
1144
1145
|
return undefined
|
|
1145
1146
|
})()
|
|
1146
1147
|
|
|
1147
1148
|
const fontOptions: WeztermFontOptions = {
|
|
1148
|
-
fontFamily,
|
|
1149
|
+
fontFamily: fontFamily ?? 'Inconsolata',
|
|
1149
1150
|
fontSize,
|
|
1150
1151
|
lineHeight,
|
|
1151
1152
|
hasBundledFonts: !!fontDirPath,
|
package/src/cli.tsx
CHANGED
|
@@ -239,13 +239,13 @@ cli
|
|
|
239
239
|
.command('release [path]', 'Build and publish extension to GitHub releases')
|
|
240
240
|
.option('--single', 'Only compile for the current platform')
|
|
241
241
|
.option('--entry <file>', 'Custom entry file (instead of auto-generated one)')
|
|
242
|
-
.action(async (extensionPath: string, options: { single?: boolean; entry?: string }) => {
|
|
243
|
-
|
|
242
|
+
.action(async (extensionPath: string | undefined, options: { single?: boolean; entry?: string }) => {
|
|
243
|
+
const resolvedPath = path.resolve(extensionPath || process.cwd())
|
|
244
244
|
|
|
245
245
|
console.log('Building and releasing extension...')
|
|
246
246
|
try {
|
|
247
247
|
const result = await releaseExtension({
|
|
248
|
-
extensionPath,
|
|
248
|
+
extensionPath: resolvedPath,
|
|
249
249
|
single: options.single,
|
|
250
250
|
entry: options.entry,
|
|
251
251
|
})
|
|
@@ -279,7 +279,7 @@ cli
|
|
|
279
279
|
.option('--theme <name>', 'Default theme name (default: nerv)')
|
|
280
280
|
.action(
|
|
281
281
|
async (
|
|
282
|
-
extensionPath: string,
|
|
282
|
+
extensionPath: string | undefined,
|
|
283
283
|
options: {
|
|
284
284
|
name?: string
|
|
285
285
|
icon?: string
|
|
@@ -294,6 +294,8 @@ cli
|
|
|
294
294
|
fontSize?: string
|
|
295
295
|
lineHeight?: string
|
|
296
296
|
theme?: string
|
|
297
|
+
// `--no-installer` adds noInstaller to the inferred type
|
|
298
|
+
noInstaller?: boolean
|
|
297
299
|
},
|
|
298
300
|
) => {
|
|
299
301
|
extensionPath = path.resolve(extensionPath || process.cwd())
|
|
@@ -597,7 +599,7 @@ cli
|
|
|
597
599
|
'Search for extensions in the Raycast store',
|
|
598
600
|
)
|
|
599
601
|
.option('-n, --limit [number]', 'Number of results to show (default: 10)')
|
|
600
|
-
.action(async (query
|
|
602
|
+
.action(async (query, options) => {
|
|
601
603
|
try {
|
|
602
604
|
const limit = parseInt(options.limit || '10', 10)
|
|
603
605
|
const result = await searchStoreListings({ query, perPage: limit })
|
|
@@ -642,15 +644,12 @@ cli
|
|
|
642
644
|
'--no-dir',
|
|
643
645
|
'Put files directly in output directory instead of creating extension subdirectory',
|
|
644
646
|
)
|
|
645
|
-
.action(
|
|
646
|
-
async (
|
|
647
|
-
extensionName: string,
|
|
648
|
-
options: { output?: string; dir: boolean },
|
|
649
|
-
) => {
|
|
647
|
+
.action(async (extensionName, options) => {
|
|
650
648
|
try {
|
|
651
649
|
const destPath = path.resolve(options.output || '.')
|
|
652
|
-
// When --no-dir is passed,
|
|
653
|
-
const
|
|
650
|
+
// When --no-dir is passed, noDir is true; put files directly in destPath
|
|
651
|
+
const useSubdir = !options.noDir
|
|
652
|
+
const extensionDir = useSubdir
|
|
654
653
|
? path.join(destPath, extensionName)
|
|
655
654
|
: destPath
|
|
656
655
|
const tempCloneDir = path.join(
|
|
@@ -662,7 +661,7 @@ cli
|
|
|
662
661
|
`Downloading extension '${extensionName}' from raycast/extensions...`,
|
|
663
662
|
)
|
|
664
663
|
|
|
665
|
-
if (
|
|
664
|
+
if (useSubdir && fs.existsSync(extensionDir)) {
|
|
666
665
|
console.log(`Removing existing directory: ${extensionDir}`)
|
|
667
666
|
fs.rmSync(extensionDir, { recursive: true, force: true })
|
|
668
667
|
}
|
|
@@ -724,7 +723,7 @@ cli
|
|
|
724
723
|
}
|
|
725
724
|
|
|
726
725
|
// Move files to final destination
|
|
727
|
-
if (
|
|
726
|
+
if (useSubdir) {
|
|
728
727
|
fs.mkdirSync(extensionDir, { recursive: true })
|
|
729
728
|
}
|
|
730
729
|
const filesToMove = fs.readdirSync(extensionPath)
|
|
@@ -755,7 +754,7 @@ cli
|
|
|
755
754
|
|
|
756
755
|
cli
|
|
757
756
|
.command('new [name]', 'Create a new termcast extension')
|
|
758
|
-
.action(async (name: string) => {
|
|
757
|
+
.action(async (name: string | undefined) => {
|
|
759
758
|
if (!name) {
|
|
760
759
|
console.log('Usage: termcast new <extension-name>\n')
|
|
761
760
|
console.log('Create a new termcast extension with the given name.\n')
|
package/src/compile.vitest.tsx
CHANGED
|
@@ -96,7 +96,7 @@ test('compile extension and run executable', async () => {
|
|
|
96
96
|
Show State Shows the current application state in view
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
↵ run command ↑↓ navigate ^k actions
|
|
99
|
+
↵ run command ↑↓ navigate ^k actions :vim
|
|
100
100
|
"
|
|
101
101
|
`)
|
|
102
102
|
}, 60000)
|
|
@@ -198,7 +198,7 @@ test('compiled executable can navigate back', async () => {
|
|
|
198
198
|
○ Fifth Item This is the fifth item
|
|
199
199
|
|
|
200
200
|
|
|
201
|
-
↵ copy item title ↑↓ navigate ^k actions
|
|
201
|
+
↵ copy item title ↑↓ navigate ^k actions :vim
|
|
202
202
|
"
|
|
203
203
|
`)
|
|
204
204
|
}, 60000)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { platform } from '#platform/runtime'
|
|
1
2
|
import React, {
|
|
2
3
|
type ReactNode,
|
|
3
4
|
type ReactElement,
|
|
@@ -22,6 +23,7 @@ import { Dropdown } from 'termcast/src/components/dropdown'
|
|
|
22
23
|
import { ExtensionPreferences } from 'termcast/src/components/extension-preferences'
|
|
23
24
|
import { ThemePicker } from 'termcast/src/components/theme-picker'
|
|
24
25
|
import { useStore } from 'termcast/src/state'
|
|
26
|
+
import { toggleVimMode } from 'termcast/src/vim-mode'
|
|
25
27
|
import { InFocus } from 'termcast/src/internal/focus-context'
|
|
26
28
|
import { Onscreen, useIsOffscreen } from 'termcast/src/internal/offscreen'
|
|
27
29
|
import { CommonProps } from 'termcast/src/utils'
|
|
@@ -587,7 +589,7 @@ Action.ToggleQuickLook = (props) => {
|
|
|
587
589
|
return
|
|
588
590
|
}
|
|
589
591
|
|
|
590
|
-
if (
|
|
592
|
+
if (platform !== 'darwin') {
|
|
591
593
|
showToast({
|
|
592
594
|
title: 'Quick Look',
|
|
593
595
|
message: 'Quick Look is only supported on macOS',
|
|
@@ -743,6 +745,21 @@ export function matchesShortcut(
|
|
|
743
745
|
return true
|
|
744
746
|
}
|
|
745
747
|
|
|
748
|
+
// Separate component so the inputMode selector is reactive and the label
|
|
749
|
+
// updates when vim mode is toggled without reopening the action panel.
|
|
750
|
+
function VimModeAction(): any {
|
|
751
|
+
const inputMode = useStore((s) => s.inputMode)
|
|
752
|
+
return (
|
|
753
|
+
<Action
|
|
754
|
+
title={inputMode === 'vim' ? 'Disable Vim Mode' : 'Enable Vim Mode'}
|
|
755
|
+
onAction={() => {
|
|
756
|
+
useStore.setState({ showActionsDialog: false })
|
|
757
|
+
toggleVimMode()
|
|
758
|
+
}}
|
|
759
|
+
/>
|
|
760
|
+
)
|
|
761
|
+
}
|
|
762
|
+
|
|
746
763
|
/**
|
|
747
764
|
* ActionPanel uses React portals to render its dialog content in the overlay
|
|
748
765
|
* area while staying in the original React tree. This preserves all React
|
|
@@ -916,6 +933,7 @@ const ActionPanel: ActionPanelType = (props) => {
|
|
|
916
933
|
dialog.push({ element: <ThemePicker /> })
|
|
917
934
|
}}
|
|
918
935
|
/>
|
|
936
|
+
<VimModeAction />
|
|
919
937
|
<Action
|
|
920
938
|
title="Toggle Console Logs"
|
|
921
939
|
onAction={() => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import
|
|
3
|
-
import path from 'node:path'
|
|
2
|
+
import { fileExists, readFileSync, joinPath, dirname } from '#platform/runtime'
|
|
4
3
|
import { useQuery } from '@tanstack/react-query'
|
|
5
4
|
import { Form } from './form'
|
|
6
5
|
import { showToast, Toast } from '../apis/toast'
|
|
@@ -55,20 +54,20 @@ export function ExtensionPreferences({
|
|
|
55
54
|
if (extensionPackageJson?.name === extensionName) {
|
|
56
55
|
// Dev mode or compiled extension - use package.json from state
|
|
57
56
|
packageJson = extensionPackageJson
|
|
58
|
-
} else if (extensionPath &&
|
|
57
|
+
} else if (extensionPath && fileExists(joinPath(extensionPath, 'package.json'))) {
|
|
59
58
|
// Dev mode with extensionPath - read from disk
|
|
60
|
-
packageJson = JSON.parse(
|
|
59
|
+
packageJson = JSON.parse(readFileSync(joinPath(extensionPath, 'package.json')))
|
|
61
60
|
} else {
|
|
62
61
|
// Store extension - read from store directory
|
|
63
62
|
const storeDir = getStoreDirectory()
|
|
64
|
-
const extensionDir =
|
|
65
|
-
const packageJsonPath =
|
|
63
|
+
const extensionDir = joinPath(storeDir, extensionName)
|
|
64
|
+
const packageJsonPath = joinPath(extensionDir, 'package.json')
|
|
66
65
|
|
|
67
|
-
if (!
|
|
66
|
+
if (!fileExists(packageJsonPath)) {
|
|
68
67
|
throw new Error(`Extension ${extensionName} not found`)
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
packageJson = JSON.parse(
|
|
70
|
+
packageJson = JSON.parse(readFileSync(packageJsonPath))
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
let prefsToUse: PreferenceManifest[] = []
|
|
@@ -5,9 +5,9 @@ import { searchFiles, parsePath } from '../../utils/file-system'
|
|
|
5
5
|
import { useKeyboard } from '@opentui/react'
|
|
6
6
|
import { useIsInFocus } from 'termcast/src/internal/focus-context'
|
|
7
7
|
import { createStore, useStore } from 'zustand'
|
|
8
|
-
import
|
|
8
|
+
import { homedir as getHomedir } from '#platform/runtime'
|
|
9
9
|
|
|
10
|
-
const homedir =
|
|
10
|
+
const homedir = getHomedir()
|
|
11
11
|
|
|
12
12
|
interface FileAutocompleteState {
|
|
13
13
|
filter: string
|