We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When I scroll this swift file with 387 LOC:
import Foundation import AVFoundation import CoreGraphics import VideoToolbox import AppKit // MARK: - Virtual Desktop Handler class VirtualDesktopManager { private var displayStream: CGDisplayStream? private let queue = DispatchQueue(label: "com.videostreaming.capture") func startCapturing(width: Int, height: Int, handler: @escaping (CGImage?) -> Void) { print("Checking screen recording permissions...") // Check screen recording permission if CGPreflightScreenCaptureAccess() { print("Screen recording permission already granted") } else { print("Requesting screen recording permission...") CGRequestScreenCaptureAccess() // Wait for permission while !CGPreflightScreenCaptureAccess() { Thread.sleep(forTimeInterval: 0.1) } print("Screen recording permission granted") } print("Starting screen capture...") let displayID = CGMainDisplayID() // Get the display bounds let displayWidth = CGDisplayPixelsWide(displayID) let displayHeight = CGDisplayPixelsHigh(displayID) // Calculate scaled dimensions while maintaining aspect ratio let scale = min(Double(width) / Double(displayWidth), Double(height) / Double(displayHeight)) let scaledWidth = Int(Double(displayWidth) * scale) let scaledHeight = Int(Double(displayHeight) * scale) print("Display dimensions: \(displayWidth)x\(displayHeight)") print("Scaled dimensions: \(scaledWidth)x\(scaledHeight)") let properties: [CFString: Any] = [ CGDisplayStream.showCursor: true, CGDisplayStream.minimumFrameTime: 1.0/30.0 ] displayStream = CGDisplayStream( dispatchQueueDisplay: displayID, outputWidth: scaledWidth, outputHeight: scaledHeight, pixelFormat: Int32(kCVPixelFormatType_32BGRA), properties: properties as CFDictionary, queue: queue, handler: { [weak self] (status, displayTime, frameSurface, error) in guard let self = self else { return } switch status { case .frameComplete: if let frameSurface = frameSurface, let image = self.createCGImage(from: frameSurface) { handler(image) } case .stopped: print("Display stream stopped") case .frameBlank: print("Frame blank") case .frameIdle: print("Frame idle") @unknown default: print("Unknown frame status: \(status)") } } ) if displayStream == nil { print("Failed to create display stream") return } print("Starting display stream...") if let startError = displayStream?.start() { print("Display stream start failed with error: \(startError)") // Print error code print("Error code: \(startError.rawValue)") // Handle common error cases switch startError.rawValue { case 1000: print("Permission denied or not available") case 1001: print("Invalid display") case 1002: print("Invalid parameters") default: print("Unknown error") } } else { print("Display stream started successfully") } } private func createCGImage(from surface: IOSurfaceRef) -> CGImage? { let width = IOSurfaceGetWidth(surface) let height = IOSurfaceGetHeight(surface) let bytesPerRow = IOSurfaceGetBytesPerRow(surface) let surfaceData = IOSurfaceGetBaseAddress(surface) guard let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) else { return nil } let context = CGContext( data: surfaceData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue ) return context?.makeImage() } func stopCapturing() { print("Stopping screen capture...") displayStream?.stop() displayStream = nil } } // MARK: - Video Streaming Manager class VideoStreamingManager { private let desktopManager = VirtualDesktopManager() private let encoder: VideoEncoder private let streamServer = StreamServer() private var frameCount: Int64 = 0 private let width: Int32 private let height: Int32 private let clientAddress: String private let clientPort: UInt16 init(width: Int32, height: Int32, clientAddress: String, clientPort: UInt16) { self.width = width self.height = height self.clientAddress = clientAddress self.clientPort = clientPort self.encoder = VideoEncoder(width: width, height: height) print("VideoStreamingManager initialized") } func startCapture() { print("Starting video capture and streaming...") do { try streamServer.startServer(port: 12345) streamServer.setClient(address: clientAddress, port: clientPort) print("UDP server started on port 12345, sending to \(clientAddress):\(clientPort)") desktopManager.startCapturing(width: Int(width), height: Int(height)) { [weak self] cgImage in guard let self = self, let image = cgImage else { return } let timestamp = CMTime(value: self.frameCount, timescale: 30) self.frameCount += 1 if self.frameCount % 30 == 0 { print("Processed \(self.frameCount) frames") } self.encoder.encode(image: image, presentationTimeStamp: timestamp) { encodedData in if let data = encodedData { do { var header = PacketHeader( frameNumber: UInt32(self.frameCount), timestamp: UInt64(timestamp.value), payloadSize: UInt32(data.count) ) var packetData = Data(bytes: &header, count: MemoryLayout<PacketHeader>.size) packetData.append(data) try self.streamServer.send(data: packetData) } catch { print("Error sending frame \(self.frameCount): \(error)") } } } } } catch { print("Error starting capture: \(error)") } } func stopCapture() { print("Stopping video capture and streaming...") desktopManager.stopCapturing() streamServer.closeConnection() } deinit { stopCapture() } } // MARK: - Video Encoder class VideoEncoder { private var session: VTCompressionSession? private let width: Int32 private let height: Int32 private let fps: Int32 init(width: Int32, height: Int32, fps: Int32 = 30) { self.width = width self.height = height self.fps = fps setupSession() } private func setupSession() { var session: VTCompressionSession? let status = VTCompressionSessionCreate( allocator: kCFAllocatorDefault, width: width, height: height, codecType: kCMVideoCodecType_H264, encoderSpecification: nil, imageBufferAttributes: nil, compressedDataAllocator: nil, outputCallback: nil, refcon: nil, compressionSessionOut: &session ) guard status == noErr, let session = session else { return } VTSessionSetProperty(session, key: kVTCompressionPropertyKey_RealTime, value: kCFBooleanTrue) VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_H264_Main_AutoLevel) VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AverageBitRate, value: NSNumber(value: 2000000)) VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ExpectedFrameRate, value: NSNumber(value: fps)) VTCompressionSessionPrepareToEncodeFrames(session) self.session = session } func encode(image: CGImage, presentationTimeStamp: CMTime, completion: @escaping (Data?) -> Void) { guard let session = session else { return } var pixelBuffer: CVPixelBuffer? let status = CVPixelBufferCreate( kCFAllocatorDefault, image.width, image.height, kCVPixelFormatType_32BGRA, nil, &pixelBuffer ) guard status == kCVReturnSuccess, let pixelBuffer = pixelBuffer else { return } CVPixelBufferLockBaseAddress(pixelBuffer, []) let context = CGContext( data: CVPixelBufferGetBaseAddress(pixelBuffer), width: image.width, height: image.height, bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer), space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue ) context?.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height)) CVPixelBufferUnlockBaseAddress(pixelBuffer, []) var flags: VTEncodeInfoFlags = [] VTCompressionSessionEncodeFrame( session, imageBuffer: pixelBuffer, presentationTimeStamp: presentationTimeStamp, duration: CMTime.invalid, frameProperties: nil, infoFlagsOut: &flags, outputHandler: { status, flags, sampleBuffer in guard let sampleBuffer = sampleBuffer else { return } if CMSampleBufferDataIsReady(sampleBuffer) { if let dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) { var length = 0 var dataPointer: UnsafeMutablePointer<Int8>? CMBlockBufferGetDataPointer( dataBuffer, atOffset: 0, lengthAtOffsetOut: nil, totalLengthOut: &length, dataPointerOut: &dataPointer ) if let pointer = dataPointer { let data = Data(bytes: pointer, count: length) completion(data) } } } } ) } } // MARK: - UDP Stream Server class StreamServer { private var socket: Int32 = -1 private var clientAddr: sockaddr_in? func startServer(port: UInt16) throws { socket = Darwin.socket(AF_INET, SOCK_DGRAM, 0) guard socket >= 0 else { throw NSError(domain: "Socket creation failed", code: -1) } var addr = sockaddr_in() addr.sin_family = sa_family_t(AF_INET) addr.sin_port = port.bigEndian addr.sin_addr.s_addr = INADDR_ANY.littleEndian let bindResult = withUnsafePointer(to: &addr) { ptr in ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockPtr in bind(socket, sockPtr, socklen_t(MemoryLayout<sockaddr_in>.stride)) } } guard bindResult == 0 else { throw NSError(domain: "Bind failed", code: -2) } var bufferSize = Int32(65535 * 10) setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &bufferSize, socklen_t(MemoryLayout<Int32>.size)) } func setClient(address: String, port: UInt16) { var addr = sockaddr_in() addr.sin_family = sa_family_t(AF_INET) addr.sin_port = port.bigEndian addr.sin_addr.s_addr = inet_addr(address.cString(using: .utf8)) clientAddr = addr } func send(data: Data) throws { guard let clientAddr = clientAddr else { return } let maxChunkSize = 65507 var offset = 0 while offset < data.count { let chunkSize = min(maxChunkSize, data.count - offset) let chunk = data.subdata(in: offset..<(offset + chunkSize)) let sendResult = withUnsafePointer(to: clientAddr) { ptr in ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockPtr in chunk.withUnsafeBytes { buffer in sendto(socket, buffer.baseAddress, chunk.count, 0, sockPtr, socklen_t(MemoryLayout<sockaddr_in>.stride)) } } } if sendResult < 0 { throw NSError(domain: "Send failed", code: -3) } offset += chunkSize } } func closeConnection() { if socket >= 0 { close(socket) } } } // MARK: - Packet Header Structure struct PacketHeader { var frameNumber: UInt32 var timestamp: UInt64 var payloadSize: UInt32 }
It's freezes on scroll. I debugged it with stevearc/profile.nvim, and here what I got: And here is without context:
So the problem is coming from vim.treesitter.query.parse. You can analyze by yourself it, here is traces:
vim.treesitter.query.parse
With nvim-treesitter-context: https://drive.google.com/file/d/1nv_GdnRguZFtjgqA0R_hWYiX0VkiKhMn/view?usp=drive_link Without: https://drive.google.com/file/d/1MYBKxS_SE4vHTzhwG9C4mD4TYJjo6kt8/view?usp=drive_link
You can load them at https://ui.perfetto.dev/
As one of maybe stupid suggestion - could we cache query parse if file not changed? But I absolutely don't have idea how this parse works.
NVIM v0.10.1
Scroll should be smooth
Scroll freezes nvim
local plugins = { ts = "https://github.com/nvim-treesitter/nvim-treesitter", ts_context = "https://github.com/nvim-treesitter/nvim-treesitter-context", -- ADD ADDITIONAL PLUGINS THAT ARE _NECESSARY_ TO REPRODUCE THE ISSUE } for name, url in pairs(plugins) do local install_path = "/tmp/nvim/site/" .. name if vim.fn.isdirectory(install_path) == 0 then vim.fn.system({ "git", "clone", "--depth=1", url, install_path }) end vim.o.runtimepath = install_path .. "," .. vim.o.runtimepath end require("nvim-treesitter.configs").setup({ ensure_installed = { "swift" }, -- Autoinstall languages that are not installed auto_install = true, highlight = { enable = true }, indent = { enable = true }, }) -- ADD INIT.LUA SETTINGS THAT IS _NECESSARY_ FOR REPRODUCING THE ISSUE require("treesitter-context").setup({ enable = true, max_lines = 10, })
nvim --clean -u minimal.lua
The text was updated successfully, but these errors were encountered:
It already is: https://github.com/neovim/neovim/blob/master/runtime/lua/vim/treesitter/query.lua#L216
However, the cache is invalidated on garbage collection, so one cause is that your system has too much memory pressure.
Sorry, something went wrong.
@lewis6991 hmm, weird. As for memory pressure, here is a screenshot of free mem: https://github.com/user-attachments/assets/c9717223-3b50-4c46-8f0a-0064992804a7 . So only 50% of mem used, no high CPU/MEM load. And I have 36GB of ram in total
Also, another interesting observation - that doesn't happen for go files, for example.
No branches or pull requests
Description
When I scroll this swift file with 387 LOC:
Click me
It's freezes on scroll. I debugged it with stevearc/profile.nvim, and here what I got:
And here is without context:
So the problem is coming from
vim.treesitter.query.parse
. You can analyze by yourself it, here is traces:With nvim-treesitter-context: https://drive.google.com/file/d/1nv_GdnRguZFtjgqA0R_hWYiX0VkiKhMn/view?usp=drive_link
Without: https://drive.google.com/file/d/1MYBKxS_SE4vHTzhwG9C4mD4TYJjo6kt8/view?usp=drive_link
You can load them at https://ui.perfetto.dev/
As one of maybe stupid suggestion - could we cache query parse if file not changed? But I absolutely don't have idea how this parse works.
Neovim version
NVIM v0.10.1
Expected behavior
Scroll should be smooth
Actual behavior
Scroll freezes nvim
Minimal config
Steps to reproduce
nvim --clean -u minimal.lua
The text was updated successfully, but these errors were encountered: