tangled
alpha
login
or
join now
woof.monster
/
windows-terminal-raycast
0
fork
atom
launch and manage windows terminal instances with raycast
raycast
raycast-extension
0
fork
atom
overview
issues
pulls
pipelines
aliases proof of concept
woof.monster
1 month ago
c867ca0e
971db584
+176
-11
2 changed files
expand all
collapse all
unified
split
src
open-profile.tsx
utils
profile-preferences.ts
+152
-11
src/open-profile.tsx
···
1
1
-
import { Action, ActionPanel, Icon, Keyboard, List, closeMainWindow, getPreferenceValues } from "@raycast/api";
1
1
+
import {
2
2
+
Action,
3
3
+
ActionPanel,
4
4
+
Form,
5
5
+
Icon,
6
6
+
Keyboard,
7
7
+
List,
8
8
+
LocalStorage,
9
9
+
closeMainWindow,
10
10
+
getPreferenceValues,
11
11
+
showToast,
12
12
+
useNavigation,
13
13
+
} from "@raycast/api";
14
14
+
import { useForm } from "@raycast/utils";
2
15
import { execFile } from "node:child_process";
3
16
import fs from "node:fs";
4
17
import os from "node:os";
5
5
-
import { useState } from "react";
18
18
+
import { useEffect, useState } from "react";
6
19
import { Preferences } from "./types/preferences";
7
7
-
import { Profile, WindowsTerminalSettings, Folder } from "./types/windows-terminal";
20
20
+
import { Profile, WindowsTerminalSettings, Folder, FolderEntry } from "./types/windows-terminal";
21
21
+
import { getAllProfilePreferences, getProfilePreferences } from "./utils/profile-preferences";
22
22
+
import React from "react";
8
23
9
24
const preferences = getPreferenceValues<Preferences>();
10
25
const PROFILES = JSON.parse(
11
26
fs.readFileSync(`C:\\Users\\${os.userInfo().username}${preferences.release}`, "utf8"),
12
27
) as WindowsTerminalSettings;
13
28
14
14
-
function Actions(props: { profile: Profile }) {
29
29
+
// TEACH ME HOW TO SUSPEND
30
30
+
// ------------------------------------------------------------------------- //
31
31
+
// A component was suspended by an uncached promise. Creating promises inside a
32
32
+
// Client Component or hook is not yet supported, except via a
33
33
+
// Suspense-compatible library or framework.
34
34
+
// ------------------------------------------------------------------------- //
35
35
+
// this does work despite the error, though.
36
36
+
const EditAlias = React.memo(async (props: { profile: Profile }) => {
37
37
+
console.log("INVOK");
38
38
+
const { pop } = useNavigation();
39
39
+
const [getAlias, setAlias] = useState<string>("");
40
40
+
41
41
+
const { handleSubmit, itemProps, setValue } = useForm<{ alias: string }>({
42
42
+
async onSubmit(values: { alias: string }) {
43
43
+
await LocalStorage.setItem(props.profile.guid, JSON.stringify({ alias: values.alias }));
44
44
+
pop();
45
45
+
showToast({ title: `Alias set for ${props.profile.name}` });
46
46
+
},
47
47
+
validation: {
48
48
+
alias(value) {
49
49
+
if (!value) {
50
50
+
return "An alias is required";
51
51
+
} else if (value.length >= 12) {
52
52
+
return "Alias is too long";
53
53
+
}
54
54
+
},
55
55
+
},
56
56
+
});
57
57
+
58
58
+
useEffect(() => {
59
59
+
async function load() {
60
60
+
const profile = await getProfilePreferences(props.profile.guid);
61
61
+
setAlias(profile.alias);
62
62
+
// setValue("alias", getAlias);
63
63
+
console.log(getAlias);
64
64
+
}
65
65
+
load();
66
66
+
}, [props.profile.guid]);
67
67
+
68
68
+
return (
69
69
+
<Form
70
70
+
actions={
71
71
+
<ActionPanel>
72
72
+
<Action.SubmitForm
73
73
+
icon={Icon.Pencil}
74
74
+
title={getAlias ? "Update Alias" : "Set Alias"}
75
75
+
onSubmit={handleSubmit}
76
76
+
/>
77
77
+
{getAlias ? (
78
78
+
<Action.SubmitForm
79
79
+
icon={Icon.Trash}
80
80
+
title="Delete Alias"
81
81
+
shortcut={Keyboard.Shortcut.Common.Remove}
82
82
+
style={Action.Style.Destructive}
83
83
+
onSubmit={async () => {
84
84
+
await LocalStorage.removeItem(props.profile.guid);
85
85
+
// when the profile preferences gets extended, we will use this instead
86
86
+
// await LocalStorage.setItem(props.profile.guid, JSON.stringify({ alias: "" }));
87
87
+
pop();
88
88
+
showToast({ title: `Deleted alias for ${props.profile.name}` });
89
89
+
}}
90
90
+
/>
91
91
+
) : null}
92
92
+
</ActionPanel>
93
93
+
}
94
94
+
>
95
95
+
<Form.TextField placeholder={`Edit alias for ${props.profile.name}...`} autoFocus={true} {...itemProps.alias} />
96
96
+
<Form.Description
97
97
+
text={`This will be the new alias for ${props.profile.name}. You will be able to search for this profile in this extension using the alias you have set. This will not sync to Windows Terminal, or make it accessible in root search.`}
98
98
+
/>
99
99
+
</Form>
100
100
+
);
101
101
+
});
102
102
+
103
103
+
function Actions(props: { profile: Profile; alias: string }) {
104
104
+
const { push } = useNavigation();
15
105
return (
16
106
<ActionPanel title={props.profile.name}>
17
107
<Action
···
50
140
/>
51
141
)}
52
142
<ActionPanel.Section>
143
143
+
<Action
144
144
+
icon={Icon.TextCursor}
145
145
+
title={props.alias ? "Update Alias…" : "Set Alias…"}
146
146
+
shortcut={{ modifiers: ["ctrl", "shift"], key: "," }}
147
147
+
onAction={() => {
148
148
+
push(<EditAlias profile={props.profile} />);
149
149
+
}}
150
150
+
/>
151
151
+
</ActionPanel.Section>
152
152
+
<ActionPanel.Section>
53
153
<Action.Open
54
154
icon={Icon.Code}
55
155
shortcut={Keyboard.Shortcut.Common.Edit}
···
126
226
127
227
export default function Command() {
128
228
const [getFilter, setFilter] = useState("all");
229
229
+
const [getAliases, setAliases] = useState<{ [key: string]: { alias: string } }>({});
230
230
+
231
231
+
useEffect(() => {
232
232
+
async function load() {
233
233
+
const profiles = await getAllProfilePreferences();
234
234
+
setAliases(profiles);
235
235
+
}
236
236
+
load();
237
237
+
}, []);
129
238
130
239
return (
131
240
<List
···
231
340
keywords={
232
341
item.guid === "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}" || // Windows PowerShell 1.0 (comes with Windows)
233
342
item.guid === "{574e775e-4f2a-5b96-ac1e-a2962a402336}" // Windows Powershell 7.0+
234
234
-
? ["pwsh", "ps", "posh"]
343
343
+
? ["pwsh", "ps", "posh", getAliases[item.guid] ? getAliases[item.guid].alias : ""]
235
344
: item.guid === "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}"
236
236
-
? ["cmd"]
237
237
-
: []
345
345
+
? ["cmd", getAliases[item.guid] ? getAliases[item.guid].alias : ""]
346
346
+
: [
347
347
+
getAliases[item.guid] ? getAliases[item.guid].alias : ""
348
348
+
]
349
349
+
}
350
350
+
accessories={getAliases[item.guid] ? [{ tag: { value: getAliases[item.guid].alias } }] : undefined}
351
351
+
actions={
352
352
+
<Actions profile={item} alias={getAliases[item.guid] ? getAliases[item.guid].alias : ""} />
238
353
}
239
239
-
actions={<Actions profile={item} />}
240
354
/>
241
355
))}
242
356
</List.Section>
···
247
361
{PROFILES.profiles.list
248
362
.filter((item) => item.hidden !== true && item.source === "Windows.Terminal.SSH")
249
363
.map((item) => (
250
250
-
<List.Item key={item.guid} icon={Icon.Network} title={item.name} actions={<Actions profile={item} />} />
364
364
+
<List.Item
365
365
+
key={item.guid}
366
366
+
icon={Icon.Network}
367
367
+
title={item.name}
368
368
+
keywords={[getAliases[item.guid] ? getAliases[item.guid].alias : ""]}
369
369
+
accessories={getAliases[item.guid] ? [{ tag: { value: getAliases[item.guid].alias } }] : undefined}
370
370
+
actions={
371
371
+
<Actions profile={item} alias={getAliases[item.guid] ? getAliases[item.guid].alias : ""} />
372
372
+
}
373
373
+
/>
251
374
))}
252
375
</List.Section>
253
376
) : null}
···
258
381
{PROFILES.profiles.list
259
382
.filter((item) => item.hidden !== true && item.source === "Windows.Terminal.VisualStudio")
260
383
.map((item) => (
261
261
-
<List.Item key={item.guid} icon={Icon.Hammer} title={item.name} actions={<Actions profile={item} />} />
384
384
+
<List.Item
385
385
+
key={item.guid}
386
386
+
icon={Icon.Hammer}
387
387
+
title={item.name}
388
388
+
keywords={[getAliases[item.guid] ? getAliases[item.guid].alias : ""]}
389
389
+
accessories={getAliases[item.guid] ? [{ tag: { value: getAliases[item.guid].alias } }] : undefined}
390
390
+
actions={
391
391
+
<Actions profile={item} alias={getAliases[item.guid] ? getAliases[item.guid].alias : ""} />
392
392
+
}
393
393
+
/>
262
394
))}
263
395
</List.Section>
264
396
) : null}
···
274
406
item.hidden !== true && (item.source === "Microsoft.WSL" || item.source === "Windows.Terminal.Wsl"),
275
407
)
276
408
.map((item) => (
277
277
-
<List.Item key={item.guid} icon={Icon.HardDrive} title={item.name} actions={<Actions profile={item} />} />
409
409
+
<List.Item
410
410
+
key={item.guid}
411
411
+
icon={Icon.HardDrive}
412
412
+
title={item.name}
413
413
+
keywords={[getAliases[item.guid] ? getAliases[item.guid].alias : ""]}
414
414
+
accessories={getAliases[item.guid] ? [{ tag: { value: getAliases[item.guid].alias } }] : undefined}
415
415
+
actions={
416
416
+
<Actions profile={item} alias={getAliases[item.guid] ? getAliases[item.guid].alias : ""} />
417
417
+
}
418
418
+
/>
278
419
))}
279
420
</List.Section>
280
421
) : null}
+24
src/utils/profile-preferences.ts
···
1
1
+
import { LocalStorage } from "@raycast/api";
2
2
+
3
3
+
export async function getProfilePreferences(guid: string): Promise<{ alias: string }> {
4
4
+
const profile = await LocalStorage.getItem<string>(guid);
5
5
+
6
6
+
if (profile === undefined) {
7
7
+
return {
8
8
+
alias: "",
9
9
+
};
10
10
+
} else {
11
11
+
return JSON.parse(profile);
12
12
+
}
13
13
+
}
14
14
+
15
15
+
export async function getAllProfilePreferences(): Promise<{ [key: string]: { alias: string } }> {
16
16
+
const profiles = await LocalStorage.allItems<{ [key: string]: string }>();
17
17
+
const reconstructedProfiles: { [key: string]: { alias: string } } = {};
18
18
+
19
19
+
for (const i in profiles) {
20
20
+
reconstructedProfiles[i] = JSON.parse(profiles[i]);
21
21
+
}
22
22
+
23
23
+
return reconstructedProfiles;
24
24
+
}