From f7b14a0142093af5b6e53d8e51c1ad7bc4dbd5a4 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 26 Nov 2025 06:59:16 -0800 Subject: [PATCH] macos: debounce search requests with length less than 3 --- .../Sources/Ghostty/SurfaceView_AppKit.swift | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index cd8c7ccb5..071131b42 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -69,12 +69,28 @@ extension Ghostty { @Published var searchState: SearchState? = nil { didSet { if let searchState { - searchNeedleCancellable = searchState.$needle.removeDuplicates().sink { [weak self] needle in - guard let surface = self?.surface else { return } - guard needle.count > 0 else { return } - let action = "search:\(needle)" - ghostty_surface_binding_action(surface, action, UInt(action.count)) - } + // I'm not a Combine expert so if there is a better way to do this I'm + // all ears. What we're doing here is grabbing the latest needle. If the + // needle is less than 3 chars, we debounce it for a few hundred ms to + // avoid kicking off expensive searches. + searchNeedleCancellable = searchState.$needle + .removeDuplicates() + .filter { $0.count > 0 } + .map { needle -> AnyPublisher in + if needle.count >= 3 { + return Just(needle).eraseToAnyPublisher() + } else { + return Just(needle) + .delay(for: .milliseconds(300), scheduler: DispatchQueue.main) + .eraseToAnyPublisher() + } + } + .switchToLatest() + .sink { [weak self] needle in + guard let surface = self?.surface else { return } + let action = "search:\(needle)" + ghostty_surface_binding_action(surface, action, UInt(action.count)) + } } else if oldValue != nil { searchNeedleCancellable = nil guard let surface = self.surface else { return }