Skip to content

Commit 7784478

Browse files
committed
Fix bun run and bun remove completions by wiring up Rust generators
Replace Fig JavaScript generators (script/postProcess/custom) with generatorName references to Rust-based generators for bun run and bun remove subcommands. - Move get_scripts_generator() and dependencies_generator() to common.rs for reuse across npm, yarn, pnpm, and bun - Create generators/bun.rs registering shared generators for bun - Update bun.json to use generatorName instead of ignored JS generators - bun run now shows package.json scripts - bun remove now shows installed dependencies Fixes APP-3491 Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 8fafc3f commit 7784478

5 files changed

Lines changed: 104 additions & 94 deletions

File tree

command-signatures/json/bun.json

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,8 @@
314314
"description": "Run a package.json script or executable",
315315
"args": {
316316
"name": "script",
317-
"generators": {
318-
"cache": {
319-
"strategy": "stale-while-revalidate",
320-
"cacheByDirectory": true
321-
},
322-
"script": "until [[ -f package.json ]] || [[ $PWD = '/' ]]; do cd ..; done; cat package.json",
323-
"postProcess": "function(e,[t]){if(e.trim()==\"\")return[];try{let n=JSON.parse(e),i=n.scripts,a=n.fig||{};if(i)return Object.entries(i).map(([s,p])=>{let c=t===\"yarn\"?\"fig://icon?type=yarn\":\"fig://icon?type=npm\",o=a[s];return J({name:s,icon:c,description:p},o)})}catch(n){console.error(n)}return[]}"
324-
}
317+
"description": "Script to run from your package.json",
318+
"generatorName": "get_scripts_generator"
325319
}
326320
},
327321
{
@@ -688,10 +682,8 @@
688682
],
689683
"args": {
690684
"name": "package",
691-
"generators": {
692-
"trigger": "_NuFrRa_e=>e===\"-g\"||e===\"--global\"",
693-
"custom": "function(e,t){return L(this,null,function*(){var n,i;if(!e.includes(\"-g\")&&!e.includes(\"--global\")){let a=yield t(\"cat $(npm prefix)/package.json\"),s=JSON.parse(a),p=(n=s.dependencies)!=null?n:{},c=s.devDependencies,o=(i=s.optionalDependencies)!=null?i:{};return Object.assign(p,c,o),Object.keys(p).filter(d=>!e.some(f=>f===d)).map(d=>({name:d,icon:\"\\u{1F4E6}\",description:p[d]?\"dependency\":o[d]?\"optionalDependency\":\"devDependency\"}))}else return(yield t(\"ls -1 `npm root -g`\")).split(`\n`).map(s=>({name:s,icon:\"\\u{1F4E6}\",description:\"Global dependency\"}))})}"
694-
}
685+
"description": "Package to remove",
686+
"generatorName": "dependencies_generator"
695687
}
696688
},
697689
{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use warp_completion_metadata::CommandSignatureGenerators;
2+
3+
use crate::generators::common::{dependencies_generator, get_scripts_generator};
4+
5+
pub fn generator() -> CommandSignatureGenerators {
6+
CommandSignatureGenerators::new("bun")
7+
.add_generator("get_scripts_generator", get_scripts_generator())
8+
.add_generator("dependencies_generator", dependencies_generator())
9+
}

command-signatures/src/generators/common.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use serde::Deserialize;
2+
use std::collections::HashMap;
13
use warp_completion_metadata::{
24
CommandBuilder, Generator, GeneratorResults, GeneratorResultsCollector, Suggestion,
35
};
@@ -28,6 +30,92 @@ pub fn ssh_hosts_generator() -> Generator {
2830
Generator::script(CommandBuilder::single_command(SSH_CONFIG_CMD), ssh_hosts)
2931
}
3032

33+
/// Helper struct used for deserializing a package.json file into the necessary fields
34+
/// needed for generators shared across npm, yarn, pnpm, and bun.
35+
#[derive(Deserialize)]
36+
pub struct PackageJsonInfo {
37+
#[serde(default)]
38+
pub dependencies: HashMap<String, String>,
39+
40+
#[serde(default, alias = "devDependencies")]
41+
pub dev_dependencies: HashMap<String, String>,
42+
43+
#[serde(default, alias = "optionalDependencies")]
44+
pub optional_dependencies: HashMap<String, String>,
45+
46+
#[serde(default)]
47+
pub scripts: HashMap<String, String>,
48+
}
49+
50+
/// Returns a generator that lists scripts from the nearest package.json.
51+
/// Shared across npm, yarn, pnpm, and bun.
52+
pub fn get_scripts_generator() -> Generator {
53+
Generator::script(
54+
CommandBuilder::single_command(
55+
"until [[ -f package.json ]] || [[ $PWD = '/' ]]; do cd ..; done; cat package.json",
56+
),
57+
|output| {
58+
if output.trim().is_empty() {
59+
return GeneratorResults::default();
60+
}
61+
62+
let package_info: serde_json::Result<PackageJsonInfo> = serde_json::from_str(output);
63+
64+
if let Ok(package_info) = package_info {
65+
package_info
66+
.scripts
67+
.into_iter()
68+
.map(|(key, value)| Suggestion::with_description(key, value))
69+
.collect_unordered_results()
70+
} else {
71+
GeneratorResults::default()
72+
}
73+
},
74+
)
75+
}
76+
77+
/// Returns a generator that lists dependencies from the nearest package.json.
78+
/// Shared across pnpm, bun, and other package managers.
79+
pub fn dependencies_generator() -> Generator {
80+
Generator::script(
81+
CommandBuilder::single_command(
82+
"until [[ -f package.json ]] || [[ $PWD = '/' ]]; do cd ..; done; cat package.json",
83+
),
84+
|output| {
85+
if output.trim().is_empty() {
86+
return GeneratorResults::default();
87+
}
88+
89+
let package_info: serde_json::Result<PackageJsonInfo> = serde_json::from_str(output);
90+
let package_info = match package_info {
91+
Err(_) => return GeneratorResults::default(),
92+
Ok(package_info) => package_info,
93+
};
94+
95+
let mut suggestions = package_info
96+
.dependencies
97+
.into_keys()
98+
.map(|key| Suggestion::with_description(key, "dependency"))
99+
.collect::<Vec<Suggestion>>();
100+
101+
suggestions.extend(
102+
package_info
103+
.dev_dependencies
104+
.into_keys()
105+
.map(|key| Suggestion::with_description(key, "devDependency")),
106+
);
107+
108+
suggestions.extend(
109+
package_info
110+
.optional_dependencies
111+
.into_keys()
112+
.map(|key| Suggestion::with_description(key, "optionalDependency")),
113+
);
114+
suggestions.into_iter().collect_unordered_results()
115+
},
116+
)
117+
}
118+
31119
/// Returns a cross-platform generator that lists local user names.
32120
///
33121
/// Uses `getent passwd` on Linux, `dscl` on macOS, and falls back to `/etc/passwd`.

command-signatures/src/generators/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod az;
1414
mod bazel;
1515
mod bosh;
1616
mod brew;
17+
mod bun;
1718
mod cargo;
1819
mod claude;
1920
mod codex;
@@ -74,6 +75,7 @@ pub fn dynamic_command_signature_data() -> HashMap<String, DynamicCompletionData
7475
az::generator(),
7576
bosh::generator(),
7677
brew::generator(),
78+
bun::generator(),
7779
conda::generator(),
7880
defaults::generator(),
7981
dnf::generator(),

command-signatures/src/generators/npm.rs

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,12 @@ use warp_completion_metadata::{
33
GeneratorResultsCollector, Suggestion,
44
};
55

6+
use crate::generators::common::{dependencies_generator, get_scripts_generator, PackageJsonInfo};
67
use crate::generators::git::post_process_branches;
78
use serde::Deserialize;
89
use serde_json::{Result, Value};
910
use std::collections::HashMap;
1011

11-
/// Helper struct used for deserializing a npm/yarn package.json file into the necessary fields
12-
/// needed for generators.
13-
#[derive(Deserialize)]
14-
struct PackageJsonInfo {
15-
#[serde(default)]
16-
dependencies: HashMap<String, String>,
17-
18-
#[serde(default)]
19-
dev_dependencies: HashMap<String, String>,
20-
21-
#[serde(default)]
22-
optional_dependencies: HashMap<String, String>,
23-
24-
#[serde(default)]
25-
scripts: HashMap<String, String>,
26-
}
27-
2812
/// Helper struct used for deserializing an npm package.json file. Useful for deserializing a field
2913
/// from a npm package.json file where the schema differs from the yarn package.json file.
3014
#[derive(Deserialize)]
@@ -49,31 +33,6 @@ struct YarnListInfoTree {
4933
name: String,
5034
}
5135

52-
fn get_scripts_generator() -> Generator {
53-
Generator::script(
54-
CommandBuilder::single_command(
55-
"until [[ -f package.json ]] || [[ $PWD = '/' ]]; do cd ..; done; cat package.json",
56-
),
57-
|output| {
58-
if output.trim().is_empty() {
59-
return GeneratorResults::default();
60-
}
61-
62-
let package_info: Result<PackageJsonInfo> = serde_json::from_str(output);
63-
64-
if let Ok(package_info) = package_info {
65-
package_info
66-
.scripts
67-
.into_iter()
68-
.map(|(key, value)| Suggestion::with_description(key, value))
69-
.collect_unordered_results()
70-
} else {
71-
GeneratorResults::default()
72-
}
73-
},
74-
)
75-
}
76-
7736
/// Returns the list of executables located within the `node_modules` directory.
7837
fn executables_within_node_modules() -> Generator {
7938
Generator::script(CommandBuilder::single_command(
@@ -149,46 +108,6 @@ fn get_global_packages_generator() -> Generator {
149108
)
150109
}
151110

152-
fn dependencies_generator() -> Generator {
153-
Generator::script(
154-
CommandBuilder::single_command(
155-
"until [[ -f package.json ]] || [[ $PWD = '/' ]]; do cd ..; done; cat package.json",
156-
),
157-
|output| {
158-
if output.trim().is_empty() {
159-
return GeneratorResults::default();
160-
}
161-
162-
let package_info: Result<PackageJsonInfo> = serde_json::from_str(output);
163-
let package_info = match package_info {
164-
Err(_) => return GeneratorResults::default(),
165-
Ok(package_info) => package_info,
166-
};
167-
168-
let mut suggestions = package_info
169-
.dependencies
170-
.into_keys()
171-
.map(|key| Suggestion::with_description(key, "dependency"))
172-
.collect::<Vec<Suggestion>>();
173-
174-
suggestions.extend(
175-
package_info
176-
.dev_dependencies
177-
.into_keys()
178-
.map(|key| Suggestion::with_description(key, "devDependency")),
179-
);
180-
181-
suggestions.extend(
182-
package_info
183-
.optional_dependencies
184-
.into_keys()
185-
.map(|key| Suggestion::with_description(key, "optionalDependency")),
186-
);
187-
suggestions.into_iter().collect_unordered_results()
188-
},
189-
)
190-
}
191-
192111
fn workspace_generator() -> Generator {
193112
Generator::script(
194113
CommandBuilder::single_command("cat $(npm prefix)/package.json"),

0 commit comments

Comments
 (0)