forked from pop-os/shell
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplugin_scripts.ts
145 lines (107 loc) · 4.39 KB
/
plugin_scripts.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// @ts-ignore
const Me = imports.misc.extensionUtils.getCurrentExtension()
const { Gio, GLib } = imports.gi
import * as plugins from 'launcher_plugins'
import type { Ext } from 'extension'
import type { Response } from 'launcher_plugins'
/** Scripts maintained by the user */
const LOCAL: string = GLib.get_home_dir() + "/.local/share/pop-shell/scripts/"
/** Scripts maintained by this project, or the distribution */
const SYSTEM: string = "/usr/lib/pop-shell/scripts/"
interface ScriptData {
name: string
path: string
keywords: Array<string>
description: null | string
icon?: string
}
export class ScriptsBuiltin extends plugins.Builtin {
scripts: Array<ScriptData> = new Array()
filtered: Array<ScriptData> = new Array()
sums: Set<string> = new Set()
init() {
this.sums.clear()
this.scripts.splice(0)
this.load_from(LOCAL)
this.load_from(SYSTEM)
}
load_from(path: string) {
try {
const dir = Gio.file_new_for_path(path)
if (!dir.query_exists(null)) return
const entries = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
let entry;
while ((entry = entries.next_file(null)) !== null) {
const name = entry.get_name()
if (this.sums.has(name)) continue
/** Describes a script, parsed from code comments at the top of the file */
const metadata: ScriptData = {
name,
path: path + name,
keywords: new Array(),
description: null,
}
try {
const stream = Gio.DataInputStream.new(Gio.File.new_for_path(metadata.path).read(null))
while (true) {
const [bytes] = stream.read_line(null)
if (!bytes) break
let line = imports.byteArray.toString(bytes)
if (!line.startsWith("#")) break
line = line.substring(1).trim()
if (line.startsWith("name:")) {
metadata.name = line.substring(5).trim()
} else if (line.startsWith("description:")) {
metadata.description = line.substring(12).trim()
} else if (line.startsWith("icon:")) {
metadata.icon = line.substring(5).trim()
} else if (line.startsWith("keywords:")) {
metadata.keywords = line.substring(9).trim().split(/\s+/)
}
}
this.scripts.push(metadata)
this.sums.add(name)
} catch (e) {
log(`failed to read from script at ${metadata.path}: ${e}`)
continue
}
}
} catch (e) {
log(`failure to collect scripts for script plugin: ${e}`)
}
}
query(_: Ext, query: string): Response.Response {
this.filtered.splice(0)
this.selections.splice(0)
query = query.toLowerCase()
let id = 0
for (const script of this.scripts) {
let should_include = script.name.toLowerCase().includes(query)
|| script.description?.toLowerCase().includes(query)
|| script.keywords.reduce((acc: boolean, next: string) => acc || next.includes(query), false)
if (should_include) {
const selection: Response.Selection = {
id,
name: script.name,
description: script.description,
}
if (script.icon) selection.icon = script.icon
this.selections.push(selection)
this.filtered.push(script)
id += 1
}
}
return { event: "queried", selections: this.selections }
}
submit(_: Ext, id: number): Response.Response {
let script = this.filtered[id]
if (script) {
try {
GLib.spawn_command_line_async(`sh ${script.path}`)
} catch (e) {
log(`failed to spawn script at ${script.path}: ${e}`)
}
}
return { event: "noop" }
}
}