Returns syntax highlighted source code.

@param  string     $file
@param  int        $line
@param  int        $lines
@param  array|null $vars

@return string|NULL
422918
public static function highlightFile(string $file, int $line, int $lines = 15, array $vars = null): ?string
    {
        $source = @\file_get_contents($file); // @ file may not exist
        if ($source) {
            $source = static::highlightPhp($source, $line, $lines, $vars);
            if ($editor = Helpers::editorUri($file, $line)) {
                $source = \substr_replace($source, ' data-tracy-href="' . Helpers::escapeHtml($editor) . '"', 4, 0);
            }

            return $source;
        }

        return null;
    }
1370990
public function highlightLine($source) {
		$length = mb_strlen($source, 'UTF-8');
		$result = '';
		$state  = self::STATE_RUN;
		$stack  = new SplStack();
		$tags   = new SplStack();
		
		for ($pos = 0; $pos < $length; ++ $pos) {
			$char = $source[$pos];
			
			if ($state === self::STATE_RUN || $state === self::STATE_STR
			 || $state === self::STATE_STS || $state === self::STATE_CME
			 || $state === self::STATE_CML) {
				// Whitespace
				if ($char === ' ') {
					$result .= '&nbsp;';
					continue;
				}

				// Tabulation
				if ($char === "\t") {
					$result .= '&nbsp;&nbsp;&nbsp;&nbsp;';
					continue;
				}
				
				// Less than escape
				if ($char === '<') {
					$result .= '&lt;';
					continue;
				}
				
				// Greater than escape
				if ($char === '>') {
					$result .= '&gt;';
					continue;
				}
				
				// Ampersand escape
				if ($char === '&') {
					$result .=  '&amp;';
					continue;
				}
			}
			
			// State: run
			if ($state === self::STATE_RUN) {
				// Variable
				if ($char === '$') {
					$result .= '<span class="zDumpVariable">';
					$tags[]  = '</span>';
					$result .= $char;
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_VAR;
					continue;
				}
				
				// String
				if ($char === '\'') {
					$result .= '<span class="zDumpString">';
					$tags[]  = '</span>';
					$result .= '&apos;';
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_STR;
					continue;
				}
				
				// String with substitution
				if ($char === '"') {
					$result .= '<span class="zDumpString">';
					$tags[]  = '</span>';
					$result .= '&quot;';
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_STS;
					continue;
				}
				
				// Numeric
				if (preg_match('/[0-9]/', $char)) {
					$result .= '<span class="zDumpInteger">';
					$tags[]  = '</span>';
					$result .= $char;
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_NUM;
					continue;
				}
				
				// Keyword
				if (preg_match('/[a-z]/i', $char)  && $source[$pos - 1] !== '_') {
					$keyword = $char;
					$state   = self::STATE_KEY;
					continue;
				}
				
				// Point
				if ($char === '.') {
					$state = self::STATE_PNT;
					continue;
				}
				
				// Comment start
				if ($char === '/') {
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_CMT;
					continue;
				}
				
				// Comment special
				if ($char === '*' && trim(substr($source, 0, $pos)) === '') {
					$result .= '<span class="zDumpComment">*';
					$tags[]  = '</span>';
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_CME;
					continue;
				}
			}
			
			// State: Variable
			if ($state === self::STATE_VAR) {
				if (preg_match('/[a-z0-9_]/i', $char)) {
					$result .= $char;
					continue;
				}
				
				-- $pos;
				$result .= $tags->pop();
				$state   = $stack->pop();
				continue;
			}
			
			// State: String
			if ($state === self::STATE_STR) {
				// String end
				if ($char === '\'' && $source[$pos - 1] !== '\\') {
					$result .= '&apos;';
					$result .= $tags->pop();
					$state   = $stack->pop();
					continue;
				}
				
				$result .= $char;
				continue;
			}
			
			// State: String with substitution
			if ($state === self::STATE_STS) {
				// Variable
				if ($char === '$') {
					$result .= '<span class="zDumpVariable">';
					$tags[]  = '</span>';
					$result .= $char;
					$stack[] = self::STATE_STS;
					$state   = self::STATE_VAR;
					continue;
				}
				
				// String end
				if ($char === '"' && $source[$pos - 1] !== '\\') {
					$result .= '&quot;';
					$result .= $tags->pop();
					$state   = $stack->pop();
					continue;
				}
				
				$result .= $char;
				continue;
			}
			
			// State: Point
			if ($state === self::STATE_PNT) {
				if (preg_match('/[0-9]/', $char)) {
					$result .= '<span class="zDumpInteger">.';
					$tags[]  = '</span>';
					$result .= $char;
					$stack[] = self::STATE_RUN;
					$state   = self::STATE_NUM;
					continue;
				}
				
				-- $pos;
				$state   = self::STATE_RUN;
				$result .= '.';
				continue;
			}
			
			// State: Numeric
			if ($state === self::STATE_NUM) {
				if (preg_match('/[0-9\.]/', $char)) {
					$result .= $char;
					continue;
				}
				
				-- $pos;
				$result .= $tags->pop();
				$state   = $stack->pop();
				continue;
			}
			
			// State: Comment start
			if ($state === self::STATE_CMT) {
				if ($char === '/') {
					$result .= '<span class="zDumpComment">//';
					$tags[]  = '</span>';
					$state   = self::STATE_CML;
					continue;
				}
				
				if ($char === '*') {
					$result .= '<span class="zDumpComment">/*';
					$tags[]  = '</span>';
					$state   = self::STATE_CME;
					continue;
				}
				
				-- $pos;
				$state   = $stack->pop();
				$result .= '/';
				$result .= $char;
				continue;
			}
			
			// State: Comment run
			if ($state === self::STATE_CME) {
				// End
				if ($char === '/' && $source[$pos - 1] === '*') {
					$state   = $stack->pop();
					$result .= '/';
					$result .= $tags->pop();
					continue;
				}
				
				// Variable
				if ($char === '$') {
					$result .= '<span class="zDumpVariable">';
					$tags[]  = '</span>';
					$result .= $char;
					$stack[] = self::STATE_CME;
					$state   = self::STATE_VAR;
					continue;
				}
				
				// Phpdoc
				if ($char === '@') {
					$result .= '<strong>';
					$tags[]  = '</strong>';
					$result .= $char;
					$stack[] = self::STATE_CME;
					$state   = self::STATE_DOC;
					continue;
				}
				
				$result .= $char;
				continue;
			}
			
			// State: Phpdoc
			if ($state === self::STATE_DOC) {
				if (preg_match('/[a-z\-]/i', $char)) {
					$result .= $char;
					continue;
				}
				
				-- $pos;
				$result .= $tags->pop();
				$state   = $stack->pop();
				continue;
			}
			
			// State: Keyword
			if ($state === self::STATE_KEY) {
				if (preg_match('/[a-z_]/i', $char)) {
					$keyword .= $char;
					continue;
				}
				
				if (in_array($keyword, self::$keywords, true)) {
					$result .= '<span class="zDumpKeyword">' . $keyword . '</span>';
				} else {
					$result .= $keyword;
				}
				
				$result .= $char;
				$state   = self::STATE_RUN;
				continue;
			}
			
			$result .= $char;
		}
		
		// Unclosed tags
		if (! $tags->isEmpty()) {
			foreach ($tags as $tag) {
				$result .= $tag;
			}
		}
		
		return $result;
	}
1280184
protected function fixFileDoc(&$lines, $file)
    {
        // find namespace
        $namespace = false;
        $namespaceLine = '';
        $contentAfterNamespace = false;
        foreach ($lines as $i => $line) {
            if (substr(trim($line), 0, 9) === 'namespace') {
                $namespace = $i;
                $namespaceLine = trim($line);
            } elseif ($namespace !== false && trim($line) !== '') {
                $contentAfterNamespace = $i;
                break;
            }
        }

        if ($namespace !== false && $contentAfterNamespace !== false) {
            while ($contentAfterNamespace > 0) {
                array_shift($lines);
                $contentAfterNamespace--;
            }
            $lines = array_merge([
                "<?php",
                "/**",
                " * @link " . $this->link,
                " * @copyright " . $this->copyright,
                " * @license " . $this->license,
                " */",
                "",
                $namespaceLine,
                "",
            ], $lines);
        }
    }
1165533
protected function parseDirectiveLine($line, \SplFileObject $file, $lineBreaks)
    {
        $directive = new Directive();

        $args = $this->directiveRegex($line);
        $name = array_shift($args);

        if ($name === null) {
            $lineNum = $file->key();
            throw new SyntaxException($lineNum, $line, "Could not parse the name of the directive");
        }

        $directive->setName($name)
                  ->setArguments($args)
                  ->setLineBreaks($lineBreaks);

        return $directive;
    }
869150
public function getXdebugLink($file, $line = 1)
    {
        if (count($this->xdebugReplacements)) {
            $file = strtr($file, $this->xdebugReplacements);
        }

        $url = strtr($this->getXdebugLinkTemplate(), ['%f' => $file, '%l' => $line]);
        if ($url) {
            return ['url' => $url, 'ajax' => $this->getXdebugShouldUseAjax()];
        }
    }
537691
protected function getVarName($file, $line)
    {
        // Set a fallback value.
        $varname = static::UNKNOWN_VALUE;

        // Retrieve the call from the sourcecode file.
        if ($this->pool->fileService->fileIsReadable($file) === false) {
            return $varname;
        }

        $line--;

        // Now that we have the line where it was called, we must check if
        // we have several commands in there.
        $possibleCommands = explode(';', $this->pool->fileService->readFile($file, $line, $line));
        // Now we must weed out the none krexx commands.
        foreach ($possibleCommands as $key => $command) {
            if (strpos(strtolower($command), strtolower($this->pattern)) === false) {
                unset($possibleCommands[$key]);
            }
        }

        // I have no idea how to determine the actual call of krexx if we
        // are dealing with several calls per line.
        if (count($possibleCommands) === 1) {
            // Now that we have our actual call, we must remove the krexx-part
            // from it.
            foreach ($this->callPattern as $funcname) {
                // This little baby tries to resolve everything inside the
                // brackets of the kreXX call.
                preg_match('/' . $funcname . '\s*\((.*)\)\s*/u', reset($possibleCommands), $name);
                if (isset($name[1]) === true) {
                    $varname = $this->pool->encodingService->encodeString(trim($name[1], " \t\n\r\0\x0B'\""));
                    break;
                }
            }
        }

        return $varname;
    }
969968
public static function editorLink(string $file, int $line = null): string
    {
        $file = \strtr($origFile = $file, Debugger::$editorMapping);
        if ($editor = self::editorUri($origFile, $line)) {
            $file = \str_replace('\\', '/', $file);
            if (\preg_match('#(^[a-z]:)?/.{1,50}$#i', $file, $m) && \strlen($file) > \strlen($m[0])) {
                $file = '...' . $m[0];
            }
            $file = \str_replace('/', DIRECTORY_SEPARATOR, $file);

            return self::formatHtml('<a href="%" title="%">%<b>%</b>%</a>',
                $editor,
                $file . ($line ? ":$line" : ''),
                \rtrim(\dirname($file), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR,
                \basename($file),
                $line ? ":$line" : ''
            );
        }

        return self::formatHtml('<span>%</span>', $file . ($line ? ":$line" : ''));
    }
710538
public static function outputFile( File $file, array $lines )
    {
        $file_name = $file->getPath();
        $fp = fopen($file_name,"w");
        if ( $fp === FALSE ){
            throw new FileOpenException($file);
        }
        foreach( $lines as $line ){
            $res = fwrite( $fp, $line . PHP_EOL );
            if ( $res === FALSE ){
                throw new FileOutputException($file);
            }
        }
        fclose($fp);
    }
1298065
protected function templateVars($file, $vars)
    {
        $start = $this->delimiter[0];
        $end = $this->delimiter[1];

        foreach ($vars as $var) {
            $replace = $start . $var . $end;
            if (in_array($var, $this->vars)) {
                File::put($file, str_replace($replace, $this->$var, File::get($file)));
            }
        }
    }
181291
public function getFileCode($file, $line, $range = 20)
    {
        $code = file($file);
        $half = (int)($range / 2);

        $start = $line - $half;
        0 > $start && $start = 0;

        $total = count($code);
        $end = $line + $half;
        $total < $end && $end = $total;

        $len = strlen($end);

        array_unshift($code, null);
        $content = '';
        for ($i = $start; $i < $end; $i++) {
            $temp = str_pad($i, $len, 0, STR_PAD_LEFT) . ':  ' . $code[$i];
            if ($line != $i) {
                $content .= htmlspecialchars($temp, ENT_QUOTES);
            } else {
                $content .= '<strong class="text-danger">' . htmlspecialchars($temp, ENT_QUOTES) . '</strong>';
            }
        }

        return $content;
    }
1193007
public function formatFile($file, $line, $text = null)
    {
        $flags = ENT_QUOTES | ENT_SUBSTITUTE;

        if (null === $text) {
            $file = trim($file);
            $fileStr = $file;
            if (0 === strpos($fileStr, $this->rootDir)) {
                $fileStr = str_replace(['\\', $this->rootDir], ['/', ''], $fileStr);
                $fileStr = htmlspecialchars($fileStr, $flags, $this->charset);
                $fileStr = sprintf('<abbr title="%s">kernel.project_dir</abbr>/%s', htmlspecialchars($this->rootDir, $flags, $this->charset), $fileStr);
            }

            $text = sprintf('%s at line %d', $fileStr, $line);
        }

        if (false !== $link = $this->getFileLink($file, $line)) {
            return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, $flags, $this->charset), $text);
        }

        return $text;
    }
191601
public function display($file, $vars = [])
    {
        if ((DIRECTORY_SEPARATOR !== $file[0]) && (':' !== $file[1])) { // get path if not full path was sent
            $moduleFolder = $this->request->getModulePath();
            $controllerFolder = $this->request->getController();
            $viewsFolder = str_replace(['{APP_ROOT}', '{MODULE_FOLDER}', '{CONTROLLER}', '{LIBS_FOLDER}', '{DIRECTORY_SEPARATOR}'], [
                APP_ROOT, $moduleFolder, $controllerFolder, LIBS_FOLDER, DIRECTORY_SEPARATOR
            ], $this->viewsFolder);
            $file = $viewsFolder . DIRECTORY_SEPARATOR . $file . '.php';
        }
        foreach ($this->_displayVars as $k => $v) {
            $$k = $v;
        }
        foreach ($vars as $k => $v) {
            $$k = $v;
        }
        require $file;
    }
169677
public static function getLines($file)
    {
        return !is_file($file) || !is_readable($file) || !($lines = @file($file, FILE_SKIP_EMPTY_LINES)) ? [] : $lines;
    }
370000
private function get_line_style($line)
    {
        //$style = null;
        $style = null;
        if (isset($this->highlight_extra_lines_styles[$line])) {
            $style = $this->highlight_extra_lines_styles[$line];
        }
        else { // if no "extra" style assigned
            $style = $this->highlight_extra_lines_style;
        }

        return $style;
    }
806740
static public function getFileExt($file)
    {
        $s = strrchr($file, '.');
        if ($s === false)
        {
            return false;
        }
        return strtolower(trim(substr($s, 1)));
    }
1238238
public function fileExcerpt($file, $line)
    {
        if (is_readable($file)) {
            if (\extension_loaded('fileinfo')) {
                $finfo = new \finfo();

                // Check if the file is an application/octet-stream (eg. Phar file) because highlight_file cannot parse these files
                if ('application/octet-stream' === $finfo->file($file, FILEINFO_MIME_TYPE)) {
                    return;
                }
            }

            // highlight_file could throw warnings
            // see https://bugs.php.net/bug.php?id=25725
            $code = @highlight_file($file, true);
            // remove main code/span tags
            $code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
            $content = explode('<br />', $code);

            $lines = [];
            for ($i = max($line - 3, 1), $max = min($line + 3, \count($content)); $i <= $max; ++$i) {
                $lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
            }

            return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
        }
    }
790427
public static function source($file, $line)
    {
        if ($line <= 0 || is_file($file) === false) {
            return null;
        } elseif ($line > 5) {
            $init = $line - 5;
            $end  = $line + 5;
            $breakpoint = 6;
        } else {
            $init = 0;
            $end  = 5;
            $breakpoint = $line;
        }

        return array(
            'breakpoint' => $breakpoint,
            'preview' => preg_split('#\r\n|\n#',
                trim( File::portion($file, $init, $end, true), "\r\n")
            )
        );
    }