Fix loading of large source files.
authorRobert Sesek <rsesek@bluestatic.org>
Mon, 6 Apr 2020 00:23:06 +0000 (20:23 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Mon, 6 Apr 2020 00:26:28 +0000 (20:26 -0400)
BSSourceView would wait for the php NSTask to terminate before reading
from the stdout pipe. But if the highlighting output was larger than the
NSPipe buffer, php would fill the buffer and hang in write() waiting for
available space. Instead, start reading the stdout pipe immediately
after launching the task.

CHANGES
Source/BSSourceView.mm

diff --git a/CHANGES b/CHANGES
index 005eec3c429dc3642ece126116e0337852a17f0b..4bd0c0c53af30c8ef830c19ca54d3bac22dc183c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,7 @@ MacGDBp                                                               CHANGE LOG
 - Fix: #260  Use macOS standard colors for syntax highlighting for better dark-
   mode compatibility.
 - Change: Improve toolbar buttons under dark mode.
+- Fix: #261  Large source files would fail to load.
 
 2.0 Beta 1
 #####################
index 7899dfc1ad341dcea8461880dbfa95841c011675..048dd3acbf36c98424be34a4874a873f8cc3ca9d 100644 (file)
@@ -219,15 +219,24 @@ NSString* ColorHEXStringINIDirective(NSString* directive, NSColor* color) {
     ]];
     [task setStandardOutput:outPipe];
     [task setStandardError:errPipe];
-    [task setTerminationHandler:^(NSTask*) {
-      NSMutableAttributedString* source;
+    [task setTerminationHandler:^(NSTask* taskBlock) {
+      if (task.terminationStatus != 0) {
+        NSLog(@"Failed to highlight PHP file %@. Termination status=%d. stderr: %@",
+              filePath, taskBlock.terminationStatus, [[errPipe fileHandleForReading] readDataToEndOfFile]);
+      }
+    }];
+    [task launch];
 
-      if (task.terminationStatus == 0) {
-        NSData* data = [[outPipe fileHandleForReading] readDataToEndOfFile];
-        source =
-            [[NSMutableAttributedString alloc] initWithHTML:data
-                                                    options:@{ NSCharacterEncodingDocumentAttribute : @(NSUTF8StringEncoding) }
-                                         documentAttributes:nil];
+    // Start reading the stdout pipe on a background queue. This is separate
+    // from the terminiationHandler, since a large file could be greater than
+    // the pipe buffer.
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
+      NSMutableAttributedString* source;
+      NSData* data = [[outPipe fileHandleForReading] readDataToEndOfFile];
+      if (data.length) {
+        source = [[NSMutableAttributedString alloc] initWithHTML:data
+                                                         options:@{ NSCharacterEncodingDocumentAttribute : @(NSUTF8StringEncoding) }
+                                              documentAttributes:nil];
 
         // PHP uses &nbsp; in the highlighted output, which should be converted
         // back to normal spaces.
@@ -237,8 +246,6 @@ NSString* ColorHEXStringINIDirective(NSString* directive, NSColor* color) {
         // Override the default font from Courier.
         [source addAttributes:@{ NSFontAttributeName : [[self class] sourceFont] }
                         range:NSMakeRange(0, source.length)];
-      } else {
-        NSLog(@"Failed to highlight PHP file %@: %@", filePath, [[errPipe fileHandleForReading] readDataToEndOfFile]);
       }
 
       dispatch_async(dispatch_get_main_queue(), ^{
@@ -253,8 +260,7 @@ NSString* ColorHEXStringINIDirective(NSString* directive, NSColor* color) {
         if (handler)
           handler();
       });
-    }];
-    [task launch];
+    });
   } @catch (NSException* exception) {
     // If the PHP executable is not available then the NSTask will throw an exception
     NSLog(@"Failed to highlight file: %@", exception);