From 533f3bd618824a2b13588e705a63b5b4692e9cc9 Mon Sep 17 00:00:00 2001 From: hyraxai Date: Mon, 1 Jun 2026 11:18:16 -0700 Subject: [PATCH] Add process filter feature Add argument and feature to filter processes by PID or name --- Src/args.swift | 11 ++++++++++- Src/main.swift | 20 ++++++++++++++++++-- Src/node.swift | 24 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Src/args.swift b/Src/args.swift index 9446337..6070444 100644 --- a/Src/args.swift +++ b/Src/args.swift @@ -20,7 +20,8 @@ class ArgManager { var showpid = true var showpath = true var toFile: String? - let availableArgs = ["--nocolor", "--timeline", "--timestamps", "-o", "--standard", "--version", "--sources", "--nonetwork", "--nopid", "--nopath"] + var filterParent: String? + let availableArgs = ["--nocolor", "--timeline", "--timestamps", "-o", "--standard", "--version", "--sources", "--nonetwork", "--nopid", "--nopath", "--filter"] init(suppliedArgs: [String]) { setArgs(suppliedArgs) @@ -57,6 +58,13 @@ class ArgManager { } else { toFile = "tree_output.txt" } + } else if arg == "--filter" { + if args.count > x+1 && !availableArgs.contains(args[x+1]) { + filterParent = args[x+1] + } else { + print("--filter requires a PID or process name argument") + exit(1) + } } else { print("Unidentified argument " + arg) exit(1) @@ -75,6 +83,7 @@ class ArgManager { print("--nopath Print process name only instead of full paths") print("--version Print the TrueTree version number") print("-o Output to file") + print("--filter Show only the subtree rooted at the matching process") exit(0) } } diff --git a/Src/main.swift b/Src/main.swift index 7499b12..03744fb 100644 --- a/Src/main.swift +++ b/Src/main.swift @@ -32,6 +32,19 @@ guard rootNode != nil else { exit(1) } +// Helper: resolve the subtree root when --filter is supplied +func resolveFilterRoot(from root: Node) -> Node { + guard let filter = argManager.filterParent else { return root } + if let pid = Int(filter), let found = root.search(pid: pid) { + return found + } + if let found = root.search(name: filter) { + return found + } + print("No process matching '\(filter)' was found in the tree.") + exit(1) +} + // If standard tree mode is active if argManager.standardMode { @@ -42,7 +55,9 @@ if argManager.standardMode { // Assign this process as a child parentNode?.add(child: proc.node) } - rootNode?.printTree() + + let printRoot = resolveFilterRoot(from: rootNode!) + printRoot.printTree() exit(0) } @@ -93,5 +108,6 @@ for proc in pc.processes { } // print the launchd pid and all of it's children -rootNode?.printTree() +let printRoot = resolveFilterRoot(from: rootNode!) +printRoot.printTree() diff --git a/Src/node.swift b/Src/node.swift index 6ecf6fa..c26d78e 100644 --- a/Src/node.swift +++ b/Src/node.swift @@ -51,6 +51,30 @@ final class Node { } return nil } + + func search(pid: Int) -> Node? { + if self.pid == pid { + return self + } + for child in children { + if let found = child.search(pid: pid) { + return found + } + } + return nil + } + + func search(name: String) -> Node? { + if fileName.lowercased() == name.lowercased() || path.lowercased().contains(name.lowercased()) { + return self + } + for child in children { + if let found = child.search(name: name) { + return found + } + } + return nil + } }