Open quolpr opened 1 week ago
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.
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.
@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.
Description
When I scroll this swift file with 387 LOC:
Click me
```swift 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: MemoryLayoutIt'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