Skip to content

Commit 882eea8

Browse files
committed
feat(origin): refine tracing and field controls
1 parent d245d6c commit 882eea8

8 files changed

Lines changed: 3192 additions & 166 deletions

File tree

grapha/src/fields.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ impl Default for FieldSet {
3030
}
3131

3232
impl FieldSet {
33+
pub fn with_id(mut self) -> Self {
34+
self.id = true;
35+
self
36+
}
37+
3338
pub fn all() -> Self {
3439
Self {
3540
file: true,
@@ -58,7 +63,7 @@ impl FieldSet {
5863

5964
pub fn parse(input: &str) -> Self {
6065
match input.trim() {
61-
"all" => Self::all(),
66+
"all" | "full" => Self::all(),
6267
"none" => Self::none(),
6368
s => {
6469
let mut fs = Self::none();

grapha/src/main.rs

Lines changed: 152 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ enum TraceDirection {
6262
Reverse,
6363
}
6464

65+
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
66+
enum OriginTerminalFilter {
67+
Network,
68+
Persistence,
69+
Cache,
70+
Event,
71+
Keychain,
72+
Search,
73+
}
74+
75+
impl OriginTerminalFilter {
76+
const fn as_str(self) -> &'static str {
77+
match self {
78+
Self::Network => "network",
79+
Self::Persistence => "persistence",
80+
Self::Cache => "cache",
81+
Self::Event => "event",
82+
Self::Keychain => "keychain",
83+
Self::Search => "search",
84+
}
85+
}
86+
}
87+
6588
#[derive(Subcommand)]
6689
enum Commands {
6790
/// Analyze source files and output graph
@@ -168,7 +191,7 @@ enum SymbolCommands {
168191
/// Include source snippet and relationships in results
169192
#[arg(long)]
170193
context: bool,
171-
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "all"/"none")
194+
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "full"/"all"/"none")
172195
#[arg(long)]
173196
fields: Option<String>,
174197
},
@@ -182,7 +205,7 @@ enum SymbolCommands {
182205
/// Output format
183206
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
184207
format: QueryOutputFormat,
185-
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "all"/"none")
208+
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "full"/"all"/"none")
186209
#[arg(long)]
187210
fields: Option<String>,
188211
},
@@ -199,7 +222,7 @@ enum SymbolCommands {
199222
/// Output format
200223
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
201224
format: QueryOutputFormat,
202-
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "all"/"none")
225+
/// Fields to display (comma-separated: file,id,module,span,snippet,visibility,signature,role; or "full"/"all"/"none")
203226
#[arg(long)]
204227
fields: Option<String>,
205228
},
@@ -239,6 +262,9 @@ enum FlowCommands {
239262
/// Output format
240263
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
241264
format: QueryOutputFormat,
265+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
266+
#[arg(long)]
267+
fields: Option<String>,
242268
},
243269
/// Derive a semantic effect graph from a symbol
244270
Graph {
@@ -253,6 +279,9 @@ enum FlowCommands {
253279
/// Output format
254280
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
255281
format: QueryOutputFormat,
282+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
283+
#[arg(long)]
284+
fields: Option<String>,
256285
},
257286
/// Trace backward to likely API/data origins for a UI symbol
258287
Origin {
@@ -261,12 +290,18 @@ enum FlowCommands {
261290
/// Maximum traversal depth
262291
#[arg(long, default_value = "10")]
263292
depth: usize,
293+
/// Keep only origins whose terminal kind matches
294+
#[arg(long, value_enum)]
295+
terminal_kind: Option<OriginTerminalFilter>,
264296
/// Project directory
265297
#[arg(short, long, default_value = ".")]
266298
path: PathBuf,
267299
/// Output format
268300
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
269301
format: QueryOutputFormat,
302+
/// Fields to display in output (comma-separated: file,snippet; or "full"/"all"/"none")
303+
#[arg(long)]
304+
fields: Option<String>,
270305
},
271306
/// List auto-detected entry points
272307
Entries {
@@ -276,6 +311,9 @@ enum FlowCommands {
276311
/// Output format
277312
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
278313
format: QueryOutputFormat,
314+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
315+
#[arg(long)]
316+
fields: Option<String>,
279317
},
280318
}
281319

@@ -291,6 +329,9 @@ enum L10nCommands {
291329
/// Output format
292330
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
293331
format: QueryOutputFormat,
332+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
333+
#[arg(long)]
334+
fields: Option<String>,
294335
},
295336
/// Find SwiftUI usage sites for a localization key
296337
Usages {
@@ -305,6 +346,9 @@ enum L10nCommands {
305346
/// Output format
306347
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
307348
format: QueryOutputFormat,
349+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
350+
#[arg(long)]
351+
fields: Option<String>,
308352
},
309353
}
310354

@@ -329,6 +373,9 @@ enum AssetCommands {
329373
/// Output format
330374
#[arg(long, value_enum, default_value_t = QueryOutputFormat::Json)]
331375
format: QueryOutputFormat,
376+
/// Fields to display in tree output (comma-separated: file; or "full"/"all"/"none")
377+
#[arg(long)]
378+
fields: Option<String>,
332379
},
333380
}
334381

@@ -529,7 +576,8 @@ fn run_pipeline(
529576
let line_idx = snippet::LineIndex::new(&source_str);
530577
for node in &mut result.nodes {
531578
if snippet::should_extract_snippet(node.kind) {
532-
node.snippet = line_idx.extract_full_snippet(&node.span);
579+
node.snippet = line_idx
580+
.extract_symbol_snippet(&node.span, &node.name, node.kind);
533581
}
534582
}
535583
}
@@ -754,6 +802,13 @@ fn resolve_field_set(fields_flag: &Option<String>, path: &Path) -> fields::Field
754802
}
755803
}
756804

805+
fn resolve_search_field_set(fields_flag: &Option<String>, path: &Path) -> fields::FieldSet {
806+
match fields_flag {
807+
Some(_) => resolve_field_set(fields_flag, path),
808+
None => resolve_field_set(fields_flag, path).with_id(),
809+
}
810+
}
811+
757812
fn tree_render_options(color: ColorMode) -> render::RenderOptions {
758813
use std::io::IsTerminal;
759814

@@ -1033,7 +1088,7 @@ fn handle_symbol_command(
10331088
context,
10341089
fields,
10351090
} => {
1036-
let field_set = resolve_field_set(&fields, &path);
1091+
let field_set = resolve_search_field_set(&fields, &path);
10371092
let index = open_search_index(&path)?;
10381093
let options = search::SearchOptions {
10391094
kind,
@@ -1123,57 +1178,89 @@ fn handle_flow_command(
11231178
depth,
11241179
path,
11251180
format,
1181+
fields,
11261182
} => match direction {
1127-
TraceDirection::Forward => handle_resolved_graph_query(
1128-
&path,
1129-
format,
1130-
render_options,
1131-
"symbol",
1132-
|graph| query::trace::query_trace(graph, &symbol, depth.unwrap_or(10)),
1133-
render::render_trace_with_options,
1134-
),
1135-
TraceDirection::Reverse => handle_resolved_graph_query(
1136-
&path,
1137-
format,
1138-
render_options,
1139-
"symbol",
1140-
|graph| query::reverse::query_reverse(graph, &symbol, depth),
1141-
render::render_reverse_with_options,
1142-
),
1183+
TraceDirection::Forward => {
1184+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
1185+
handle_resolved_graph_query(
1186+
&path,
1187+
format,
1188+
render_options,
1189+
"symbol",
1190+
|graph| query::trace::query_trace(graph, &symbol, depth.unwrap_or(10)),
1191+
render::render_trace_with_options,
1192+
)
1193+
}
1194+
TraceDirection::Reverse => {
1195+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
1196+
handle_resolved_graph_query(
1197+
&path,
1198+
format,
1199+
render_options,
1200+
"symbol",
1201+
|graph| query::reverse::query_reverse(graph, &symbol, depth),
1202+
render::render_reverse_with_options,
1203+
)
1204+
}
11431205
},
11441206
FlowCommands::Graph {
11451207
symbol,
11461208
depth,
11471209
path,
11481210
format,
1149-
} => handle_resolved_graph_query(
1150-
&path,
1151-
format,
1152-
render_options,
1153-
"symbol",
1154-
|graph| query::dataflow::query_dataflow(graph, &symbol, depth),
1155-
render::render_dataflow_with_options,
1156-
),
1211+
fields,
1212+
} => {
1213+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
1214+
handle_resolved_graph_query(
1215+
&path,
1216+
format,
1217+
render_options,
1218+
"symbol",
1219+
|graph| query::dataflow::query_dataflow(graph, &symbol, depth),
1220+
render::render_dataflow_with_options,
1221+
)
1222+
}
11571223
FlowCommands::Origin {
11581224
symbol,
11591225
depth,
1226+
terminal_kind,
11601227
path,
11611228
format,
1162-
} => handle_resolved_graph_query(
1163-
&path,
1164-
format,
1165-
render_options,
1166-
"symbol",
1167-
|graph| query::origin::query_origin(graph, &symbol, depth),
1168-
render::render_origin_with_options,
1169-
),
1170-
FlowCommands::Entries { path, format } => handle_graph_query(
1171-
&path,
1229+
fields,
1230+
} => {
1231+
let field_set = resolve_field_set(&fields, &path);
1232+
let render_options = render_options.with_fields(field_set);
1233+
handle_resolved_graph_query(
1234+
&path,
1235+
format,
1236+
render_options,
1237+
"symbol",
1238+
|graph| {
1239+
let result =
1240+
query::origin::query_origin_with_path(graph, &symbol, depth, Some(&path))?;
1241+
let result = query::origin::filter_origin_result_by_terminal_kind(
1242+
result,
1243+
terminal_kind.map(OriginTerminalFilter::as_str),
1244+
);
1245+
Ok(query::origin::project_origin_result(result, field_set))
1246+
},
1247+
render::render_origin_with_options,
1248+
)
1249+
}
1250+
FlowCommands::Entries {
1251+
path,
11721252
format,
1173-
render_options,
1174-
query::entries::query_entries,
1175-
render::render_entries_with_options,
1176-
),
1253+
fields,
1254+
} => {
1255+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
1256+
handle_graph_query(
1257+
&path,
1258+
format,
1259+
render_options,
1260+
query::entries::query_entries,
1261+
render::render_entries_with_options,
1262+
)
1263+
}
11771264
}
11781265
}
11791266

@@ -1186,7 +1273,9 @@ fn handle_l10n_command(
11861273
symbol,
11871274
path,
11881275
format,
1276+
fields,
11891277
} => {
1278+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
11901279
let graph = load_graph(&path)?;
11911280
let catalogs = localization::load_catalog_index(&path)?;
11921281
let result = resolve_query_result(
@@ -1205,7 +1294,9 @@ fn handle_l10n_command(
12051294
table,
12061295
path,
12071296
format,
1297+
fields,
12081298
} => {
1299+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
12091300
let graph = load_graph(&path)?;
12101301
let catalogs = localization::load_catalog_index(&path)?;
12111302
let result = query::usages::query_usages(&graph, &catalogs, &key, table.as_deref());
@@ -1219,7 +1310,10 @@ fn handle_l10n_command(
12191310
}
12201311
}
12211312

1222-
fn handle_asset_command(command: AssetCommands) -> anyhow::Result<()> {
1313+
fn handle_asset_command(
1314+
command: AssetCommands,
1315+
render_options: render::RenderOptions,
1316+
) -> anyhow::Result<()> {
12231317
match command {
12241318
AssetCommands::List { unused, path } => {
12251319
if unused {
@@ -1233,7 +1327,13 @@ fn handle_asset_command(command: AssetCommands) -> anyhow::Result<()> {
12331327
print_json(&records)
12341328
}
12351329
}
1236-
AssetCommands::Usages { name, path, format } => {
1330+
AssetCommands::Usages {
1331+
name,
1332+
path,
1333+
format,
1334+
fields,
1335+
} => {
1336+
let render_options = render_options.with_fields(resolve_field_set(&fields, &path));
12371337
let graph = load_graph(&path)?;
12381338
let usages = assets::find_usages(&graph, &name);
12391339
match format {
@@ -1243,10 +1343,12 @@ fn handle_asset_command(command: AssetCommands) -> anyhow::Result<()> {
12431343
eprintln!(" no usages found for asset '{name}'");
12441344
} else {
12451345
for usage in &usages {
1246-
println!(
1247-
" {} ({}) — {}",
1248-
usage.node_name, usage.file, usage.asset_name
1249-
);
1346+
let file_label = if render_options.fields.file {
1347+
format!(" ({})", usage.file)
1348+
} else {
1349+
String::new()
1350+
};
1351+
println!(" {}{} — {}", usage.node_name, file_label, usage.asset_name);
12501352
}
12511353
}
12521354
Ok(())
@@ -1412,7 +1514,7 @@ fn main() -> anyhow::Result<()> {
14121514
Commands::Symbol { command } => handle_symbol_command(command, render_options)?,
14131515
Commands::Flow { command } => handle_flow_command(command, render_options)?,
14141516
Commands::L10n { command } => handle_l10n_command(command, render_options)?,
1415-
Commands::Asset { command } => handle_asset_command(command)?,
1517+
Commands::Asset { command } => handle_asset_command(command, render_options)?,
14161518
Commands::Repo { command } => handle_repo_command(command)?,
14171519
}
14181520

0 commit comments

Comments
 (0)