diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a46cc..f84a59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.7](https://github.com/TomasBagdanavicius/stonetable/releases/tag/v1.0.7) - 2023-06-09 + +### Changed + +- Improved responsiveness of main file and file listing loading. +- When a file is loaded and you press “R” key (and the modifier key is not held), the reload function will be called automatically. +- Qualified file paths as well as qualified namespace names that are not backed up by an existing file in filesystem will be underlined using wavy style in message text. +- Advanced PHP syntax highlighter improvements. +- PHP's "intl" extension is no longer compulsory, but recommended. +- New notifications will be shown above existing ones, instead of below them. +- Various small changes and fixes. +- Bump PHP Code Test Suite version to 1.0.7 +- Bump Project Directory version to 1.0.7 + +### Added + +- More highlighted elements with colors introduced as part of a broader initiative to colorize demo output and code messages, most notably: + - File path's basename; + - Namespace name's last component; + - Class names; + - etc. +- It’s now possible to switch to demo or unit file’s source code and back again (not to be confused with source file and its source code). A new "Toggle view" button was added to file's controls menubar. +- New API endpoint [remove-special-comments.php](src/web/api/remove-special-comments.php) that removes all special comments in a given test file. + ## [1.0.6](https://github.com/TomasBagdanavicius/stonetable/releases/tag/v1.0.6) - 2023-05-09 ### Changed diff --git a/README.md b/README.md index 60b4885..f035d8e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Stonetable is lightweight, dependency-free, conceptual PHP project build and cod ## Stonetable Web Application -![Meet Stonetable](https://www.lwis.net/stonetable/images/meet-stonetable.webp?v=2) +![Meet Stonetable](https://www.lwis.net/stonetable/images/meet-stonetable.webp?v=3) Stonetable's web application is the core component of the suite. This web app helps you navigate and visualize your PHP project builds by providing incentives to maintain organized demo and unit test files that can be outputted in a user friendly manner with enhanced state and error reporting. @@ -49,8 +49,8 @@ First off, it's important to decide where you will want to install Stonetable. T - Any web server - PHP 8.1 or higher with extensions: - - `mbstring` - - `intl` + - `mbstring` (compulsory) + - `intl` (recommended) - Any major web browser that is up to date #### Quick Run @@ -277,34 +277,34 @@ The above will output something similar to:

Undefined variable $unexisting_variable

-
Location
-
.../snippet.php:46
-
Type
+
Location
+
.../snippet.php:46
+
Type
E_WARNING
-

This is a simulated error: VendorName\snippet

+

This is a simulated error: VendorName\snippet

-
Location
-
.../snippet.php:50
-
Type
+
Location
+
.../snippet.php:50
+
Type
E_RECOVERABLE_ERROR
-
Error Class
-
Error
-
Error Code
+
Error Class
+
Error
+
Error Code
1

This is the reason

-
Location
-
.../snippet.php:53
-
Type
+
Location
+
.../snippet.php:53
+
Type
E_RECOVERABLE_ERROR
-
Error Class
-
Exception
-
Error Code
+
Error Class
+
Exception
+
Error Code
0
diff --git a/dist/stonetable/lib/php-code-test-suite/Autoload.php b/dist/stonetable/lib/php-code-test-suite/Autoload.php index 1d77ea6..ddcaeb3 100644 --- a/dist/stonetable/lib/php-code-test-suite/Autoload.php +++ b/dist/stonetable/lib/php-code-test-suite/Autoload.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/Debugger/Debugger.php b/dist/stonetable/lib/php-code-test-suite/Debugger/Debugger.php index b6bc11c..825ba5a 100644 --- a/dist/stonetable/lib/php-code-test-suite/Debugger/Debugger.php +++ b/dist/stonetable/lib/php-code-test-suite/Debugger/Debugger.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -168,11 +168,11 @@ public function traceDataToCompactLine( if( $format ) { - $result .= sprintf( - '%s', - ( $trace_data['class'] - ?? $formatter->shortenPathname($filename) ) - ); + $result .= ( isset($trace_data['class']) ) + ? $formatter->formatClassNameOrNamespace($trace_data['class']) + : $formatter::formatPathnameAddWrappers( + $formatter->shortenPathname($filename) + ); } else { @@ -180,6 +180,7 @@ public function traceDataToCompactLine( } if( !isset($trace_data['class']) && $trace_data['line'] ) { + $result .= ( $format ) ? sprintf( ':%d' @@ -190,22 +191,34 @@ public function traceDataToCompactLine( } $result .= ( $trace_data['type'] ?? ' ' ); - $result .= ( $format ) - ? sprintf( - '%s' - . '(' - . ')' - . '', - $trace_data['function'] - ) - : ($trace_data['function'] . '()'); + + if( $format ) { + + $separator_pos = strrpos($trace_data['function'], '\\'); + + if( $separator_pos === false ) { + $result .= $this->formatter->formatSimplifiedFunctionStr( + $trace_data['function'] + ); + } else { + $result .= $this->formatter->formatNamespaceName( + $trace_data['function'], + ['func'] + ) . '(' + . ')'; + } + + } else { + + $result .= ($trace_data['function'] . '()'); + } if( $format && $convert_links ) { $result = $formatter->buildIdeHtmlLink( $filename, $result, - ((int)$trace_data['line'] ?? null), + ( (int)$trace_data['line'] ?? null ), class_names: ['file'] ); } @@ -225,12 +238,19 @@ class_names: ['file'] if( is_object($arg) ) { + $class = $arg::class; + $formatted_class = $formatter->formatClassNameOrNamespace( + $class + ); $argument = ( $convert_links ) - ? $formatter->namespaceToIdeHtmlLink($arg::class) - : $arg::class; + ? $formatter->namespaceToIdeHtmlLink( + $class, + text: $formatted_class + ) + : $formatted_class; if( !$argument ) { - $argument = $arg::class; + $argument = $formatted_class; } $allow_html_entities = false; @@ -238,7 +258,7 @@ class_names: ['file'] /* Don't attempt to export and show text for the following types, eg. `var_export` will fail on large arrays containing objects with circular reference, etc. */ - } elseif( is_array($arg) && is_resource($arg) ) { + } elseif( is_array($arg) || is_resource($arg) ) { $argument = ''; @@ -249,11 +269,11 @@ class_names: ['file'] // String (can be file path or namespace name). if( - str_starts_with($argument, '\'') - && str_ends_with($argument, '\'') + str_starts_with($argument, "'") + && str_ends_with($argument, "'") ) { - $trimmed_arg = trim($argument, '\''); + $trimmed_arg = trim($argument, "'"); $length = strlen($trimmed_arg); if( $formatter->isQualifiedPathname($trimmed_arg) ) { @@ -273,12 +293,23 @@ class_names: ['file'] '\\', $trimmed_arg ); + + if( $format ) { + $namespace_formatted + = $formatter->formatClassNameOrNamespace( + $namespace + ); + } + $argument = ( $convert_links ) ? $formatter->namespaceToIdeHtmlLink( $namespace, - class_names: ['file'] + class_names: ['file'], + text: $namespace_formatted ) - : $namespace; + : ( ( $format ) + ? $namespace_formatted + : $namespace ); $allow_html_entities = false; } diff --git a/dist/stonetable/lib/php-code-test-suite/OutputText/OutputTextFormatter.php b/dist/stonetable/lib/php-code-test-suite/OutputText/OutputTextFormatter.php index 4ac2819..2432b21 100644 --- a/dist/stonetable/lib/php-code-test-suite/OutputText/OutputTextFormatter.php +++ b/dist/stonetable/lib/php-code-test-suite/OutputText/OutputTextFormatter.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -18,6 +18,8 @@ namespace PCTS\OutputText; +use PCTS\PhpTokens\EnhancedPhpToken; + class OutputTextFormatter { /** Files with the following file formats will be shortened. */ @@ -123,11 +125,52 @@ public function formatPathname( return ($pathname . $text_suffix); } - $text = ($this->shortenPathname($pathname) . $text_suffix); + return $this->formatPathnameWithText( + $pathname, + $this->shortenPathname($pathname), + $text_suffix, + $line_number, + $column_number, + $class_names + ); + } + + /** + * Formats qualified/verified pathname. + * + * @param string $pathname Path name reference. + * @param string $text Text representation of the pathname. + * @param string $suffix Text suffix to add after formatted text. + * @param int|null $line_number Line number. + * @param int|null $column_number Column number. + * @param array|null $class_names When links are used, add these classes. + * @return string If HTML formatting is enabled, HTML formatted text, + * otherwise just plain text + */ + protected function formatPathnameWithText( + string $pathname, + string $text, + string $suffix = '', + ?int $line_number = null, + ?int $column_number = null, + ?array $class_names = null + ): string { + + $file_exists = file_exists($pathname); + + if( $this->format_html ) { + $path_classes = []; + if( !$file_exists ) { + $path_classes[] = 'no-file'; + } + $text = self::formatPathnameAddWrappers($text, $path_classes); + } + + $text = ($text . $suffix); $is_link = ( $this->format_html + && $file_exists && $this->convert_links - && file_exists($pathname) ); return ( $is_link ) @@ -141,6 +184,36 @@ public function formatPathname( : $text; } + /** Adds outer and inner HTML wrappers to the given pathname. */ + public static function formatPathnameAddWrappers( + string $pathname, + array $path_classes = [], + array $base_classes = [] + ): string { + + $basename = basename($pathname); + $basename_len = strlen($basename); + $extension = pathinfo($pathname, PATHINFO_EXTENSION); + $path_classes = ['path', ...$path_classes]; + $base_classes = ['base', ...$base_classes]; + + if( $extension === 'php' ) { + $base_classes[] = 'ext-php'; + } + + return sprintf( + '', + implode(' ', $path_classes) + ) + . substr($pathname, 0, -$basename_len) + . sprintf( + '%s', + implode(' ', $base_classes), + substr($pathname, -$basename_len) + ) + . ''; + } + /** Tells if the given value is recognized as a qualified namespace. */ public function isQualifiedNamespace( string $value @@ -163,10 +236,7 @@ public function format( ): string { $result = $this->shortenFilenamesAll($text); - - if( $this->convert_links ) { - $result = $this->convertNamespacesToHtmlLinks($result); - } + $result = $this->formatNamespaces($result); return $result; } @@ -190,8 +260,8 @@ public function shortenFilenamesAll( return $text; } - /** Converts all namespaces to HTML hyperlinks in the given text string. */ - public function convertNamespacesToHtmlLinks( + /** Formats all namespaces to HTML. */ + public function formatNamespaces( string $text, ?\Closure $match_handler = null ): string { @@ -205,9 +275,10 @@ public function convertNamespacesToHtmlLinks( array_keys($this->vendor_data) ); - // Mind the "preceeded by" character group. $regex_str = sprintf( - '#(\s|^|\?|\(|"|\')((%s)[A-Za-z0-9\\\\]+)#m', + // Mind the "preceeded by" character group. + // Curly brackets "{}" are used to include "{closure}" + '#(\s|^|\?|\(|"|\'|\||:|&)((%s)[A-Za-z0-9_{}\\\\]+)#m', implode('|', $vendor_names) ); @@ -219,23 +290,62 @@ public function convertNamespacesToHtmlLinks( foreach( $matches[2] as $index => $match ) { - [$namespace, $line_number] = $match; - $vendor_name = rtrim($matches[3][$index][0], '\\'); + [$ns_name, $line_number] = $match; + [$vendor_name, $ns_start_pos] = $matches[3][$index]; + $vendor_name = rtrim($vendor_name, '\\'); + $ns_name_len = strlen($ns_name); if( !$match_handler ) { - $wrapper = $this->namespaceToIdeHtmlLink($namespace); + $ns_end_pos = ($ns_start_pos + $ns_name_len + $offset); + $is_func = ( + isset($text[$ns_end_pos]) + && $text[$ns_end_pos] === '(' + ); + $is_closure = ( + !$is_func + && EnhancedPhpToken::namespaceToParts($ns_name)['base'] + === '{closure}' + ); + $ns_name_classes = ( !$is_func ) + ? [] + : ['func']; + if( !$is_func && !$is_closure ) { + $filename = $this->namespaceToFilename($ns_name); + if( !$filename || !file_exists($filename) ) { + $ns_name_classes[] = 'no-file'; + $wrapper = $ns_name; + } elseif( $this->convert_links ) { + $wrapper = self::buildIdeHtmlLink( + $filename, + $ns_name + ); + } else { + $wrapper = $ns_name; + } + } else { + $wrapper = $ns_name; + } + $wrapper = $this->formatClassNameOrNamespace( + $wrapper, + $ns_name_classes + ); + if( $is_func || $is_closure ) { + $wrapper .= '(' + . ')'; + $ns_name_len += 2; + } } else { - $wrapper = $match_handler($namespace, $vendor_name); + $wrapper = $match_handler($ns_name, $vendor_name); } $text = substr_replace( $text, $wrapper, - ((int)$match[1] + $offset), - strlen($match[0]) + ((int)$line_number + $offset), + $ns_name_len ); - $offset += (strlen($wrapper) - strlen($match[0])); + $offset += (strlen($wrapper) - $ns_name_len); } } @@ -258,8 +368,8 @@ public function shortenFilenamesByPath( // Not preceeded by "file/". '#(?editable_file_formats) ); @@ -281,41 +391,47 @@ public function shortenFilenamesByPath( . $relative_path ); $filename_length = strlen($filename); - - $is_link = ( - $this->format_html - && $this->convert_links - && file_exists($filename) + $is_on_line = ( + isset($matches[6][$index]) + && !empty($matches[6][$index][0]) + && $matches[6][$index][1] !== -1 + ); + $is_column_num = ( + isset($matches[8][$index]) + && !empty($matches[8][$index][0]) + && $matches[8][$index][1] !== -1 + ); + $replace_text = $this->formatPathnameWithText( + $filename, + $text_relative_path, + line_number: match(true) { + $is_on_line => (int)$matches[6][$index][0], + $is_column_num => (int)$matches[8][$index][0], + default => null + }, + class_names: ['file'] ); - - $replace_text = ( $is_link ) - ? self::buildIdeHtmlLink( - $filename, - $text_relative_path, - ( (int)$matches[6][$index][0] ?: null ), - class_names: ['file'] - ) - : $text_relative_path; - $text = substr_replace( $text, $replace_text, ((int)$match[1] + $offset), $filename_length ); - $offset_add = (strlen($replace_text) - $filename_length); $offset += $offset_add; // Captured line number. if( $this->format_html - && isset($matches[6][$index]) - && !empty($matches[6][$index][0]) - && $matches[6][$index][1] !== -1 + && ($is_on_line || $is_column_num) ) { - [$line_number, $line_number_pos] = $matches[6][$index]; + if( $is_on_line ) { + [$line_number, $line_number_pos] = $matches[6][$index]; + } else { + [$line_number, $line_number_pos] = $matches[8][$index]; + } + $line_number_length = strlen($line_number); $replace_text = sprintf( '%s', @@ -338,16 +454,21 @@ class_names: ['file'] /** Converts a namespace to IDE open file HTML hyperlink. */ public function namespaceToIdeHtmlLink( string $namespace, - ?array $class_names = null + ?array $class_names = null, + ?string $text = null, ): ?string { if( !$filename = $this->namespaceToFilename($namespace) ) { return null; } + if( !file_exists($filename) ) { + return null; + } + return self::buildIdeHtmlLink( $filename, - $namespace, + ( $text ?: $namespace ), class_names: $class_names ); } @@ -416,10 +537,7 @@ public function buildIdeHtmlLink( ) ) ); - $html_link .= ( $text ) - ? $text - : $filename; - + $html_link .= ( $text ?: $filename ); $html_link .= ''; return $html_link; @@ -558,7 +676,6 @@ public static function parseIdeUriFormat( 'line' => $line_number, 'column' => $column_number, ]; - $result = $mem = ''; $format_len = strlen($ide_uri_format); $curly_stack = []; @@ -683,4 +800,95 @@ public static function parseIdeUriFormat( return $result; } + + /** HTML formats given class name - either fully qualified or keyword. */ + public function formatClassNameOrNamespace( + string $string, + array $ns_name_classes = [] + ): string { + + $separator_pos = strrpos($string, '\\'); + + // Namespace + if( $separator_pos !== false ) { + return $this->formatNamespaceName($string, $ns_name_classes); + // Class name + } else { + return sprintf( + '%s', + $string + ); + } + } + + /** + * HTML formats namespace name + * + * @param string $ns_name Namespace name. + * @param array $ns_name_classes Classes to add to namespace name wrapper. + * @return string HTML formatted namespace name. + */ + public function formatNamespaceName( + string $ns_name, + array $ns_name_classes = [] + ): string { + + $separator_pos = strrpos($ns_name, '\\'); + + if( $separator_pos === false ) { + throw new \Exception( + "Namespace name must contain backward slash separator" + ); + } + + $base = substr($ns_name, ($separator_pos + 1)); + + if( $base === '{closure}' ) { + $base = self::getFormattedClosureString(); + $ns_name_classes[] = 'closure'; + } + + $ns_name_classes = ['ns-name', ...$ns_name_classes]; + + return + sprintf( + '', + implode(' ', $ns_name_classes) + ) + . substr($ns_name, 0, ($separator_pos + 1)) + . sprintf( + '%s', + $base + ) + . ''; + } + + /** Returns HTML formatted debug string for closure. */ + public static function getFormattedClosureString(): string { + + return '{' + . 'closure' + . '}'; + } + + /** HTML formats a simplified function name string. */ + public function formatSimplifiedFunctionStr( string $func_str ): string { + + if( str_ends_with($func_str, '()') ) { + $func_str = substr($func_str, -2); + } + + $func_format = '%s'; + $punc_html = '(' + . ')'; + + if( $func_str === '{closure}' ) { + $func_str = self::getFormattedClosureString(); + } + + return (sprintf( + $func_format, + $func_str + ) . $punc_html); + } } diff --git a/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php index 3c2a911..f33bd2e 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php index 776009e..25aee47 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php b/dist/stonetable/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php index 6067b5f..2053265 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -247,7 +247,7 @@ public function richFormatErrorMessage( ) ); $result .= '
'; - $result .= '
Location
'; + $result .= '
Location
'; $line_number_suffix = sprintf( ':%d', $line_number @@ -264,7 +264,7 @@ class_names: ['file'] if( $error_type !== null ) { - $result .= '
Type
'; + $result .= '
Type
'; $result .= sprintf( '
%s
', self::errorTypeToString($error_type) @@ -324,24 +324,27 @@ public function richFormatException( close_html_tags: false ); - $exception_namespace = $exception::class; - - $result .= '
Error Class
'; + $result .= '
Error Class
'; $result .= '
'; + $exception_class = $exception::class; + $class_formatted = $this->formatter->formatClassNameOrNamespace( + $exception_class + ); - if( $this->formatter->isQualifiedNamespace($exception_namespace) ) { + if( $this->formatter->isQualifiedNamespace($exception_class) ) { $result .= $this->formatter->namespaceToIdeHtmlLink( - $exception_namespace + $exception_class, + text: $class_formatted ); } else { - $result .= $exception_namespace; + $result .= $class_formatted; } $result .= '
'; - $result .= '
Error Code
'; + $result .= '
Error Code
'; $result .= '
'; $result .= $exception->getCode(); $result .= '
'; diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/BracketsEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/BracketsEnum.php index bc17dee..daee8b2 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/BracketsEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/BracketsEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php index 9f6c55a..aaed0ff 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -45,6 +45,7 @@ class EnhancedPhpToken { 'noreturn', 'parent', 'self', + 'iterable', '__COMPILER_HALT_OFFSET__', ]; @@ -95,8 +96,8 @@ public function isLeveled(): bool { * @return bool True when found, and false when not found. */ public function lookAhead( - array|string $while, - array|string $until + int|array|string $while, + int|array|string $until ): bool { $key = ($this->cache_key + 1); @@ -171,25 +172,34 @@ public function isClassNameLookBehind(): bool { } $non_whitespace_tokens = [ - T_CLASS, T_NEW, T_INSTANCEOF, T_EXTENDS, T_INTERFACE, + T_IMPLEMENTS, T_TRAIT, T_ENUM, // Traits T_USE, T_INSTEADOF, - T_IMPLEMENTS, ]; - return $this->lookBehind([ + $main_look_behind = $this->lookBehind([ + T_WHITESPACE, + T_STRING, + T_CLASS, + ...$non_whitespace_tokens + ], [T_CLASS, ...$non_whitespace_tokens]); + + #review: what role does comma exactly play? + $with_comma_look_behind = $this->lookBehind([ T_WHITESPACE, ',', T_STRING, ...$non_whitespace_tokens ], $non_whitespace_tokens); + + return $main_look_behind || $with_comma_look_behind; } /** @@ -211,9 +221,11 @@ public function isNakedLookBehind( int $token_id ): bool { /** * Tells if current token might be a class name in catch clause. */ - public function isClassNameLookBehindForCatch(): bool { + public function isClassNameLookBehindForCatch( + int|string|array $is = T_STRING + ): bool { - return ( !$this->token->is(T_STRING) ) + return ( !$this->token->is($is) ) ? false : $this->lookBehind([ T_WHITESPACE, @@ -252,6 +264,10 @@ public function isClassNameLookAhead(): bool { return $this->lookAhead( [T_WHITESPACE, T_VARIABLE, '|'], [T_VARIABLE, '|'], + // Not preceeded by double colons. + ) && !$this->lookBehind( + [T_WHITESPACE, T_DOUBLE_COLON, T_PAAMAYIM_NEKUDOTAYIM], + [T_DOUBLE_COLON, T_PAAMAYIM_NEKUDOTAYIM] ); } @@ -687,10 +703,13 @@ public function getInnerHtml(): string { */ public function getNamespaceLastComponentType(): ?NUDTE { - $type = NUDTE::CLASS_LIKE; + $type = NUDTE::CONSTANT; + $identified = false; if( $context = $this->stream->getContext() ) { + $identified = true; + if( $context instanceof NamespaceUseDeclarationBuilder ) { /* If there is a block statement in front, do not mark the last @@ -706,6 +725,43 @@ public function getNamespaceLastComponentType(): ?NUDTE { // Namespace definition will be presented as generic string. $type = null; + + } else { + + $identified = false; + } + + } elseif( + /* `isFunctionLookAhead` will not work here, because it can be a + "name" class token. */ + $this->lookAhead([T_WHITESPACE, '('], '(') + && !$this->lookBehind([T_WHITESPACE, T_NEW], T_NEW) + ) { + + $type = NUDTE::FUNCTION; + $identified = true; + } + + if( !$identified ) { + + $ns_name_parts = self::namespaceToParts($this->token->text); + + if( + ($ns_name_parts['vendor'] && !$ns_name_parts['base']) + || (!$ns_name_parts['vendor'] && $ns_name_parts['base']) + || $this->lookAhead( + [T_WHITESPACE, T_DOUBLE_COLON], + T_DOUBLE_COLON + ) + || $this->lookBehind([T_WHITESPACE, T_NEW], T_NEW) + || $this->lookBehind([T_WHITESPACE, T_USE], T_USE) + || $this->isClassNameLookBehindForCatch([ + T_NAMESPACE, + T_NAME_QUALIFIED, + T_NAME_FULLY_QUALIFIED + ]) + ) { + $type = NUDTE::CLASS_LIKE; } } @@ -838,4 +894,38 @@ public static function getNamespaceInnerHtml( return $result; } + + /** Returns parts for a given namespace name. */ + public static function namespaceToParts( string $ns_name ): array { + + $divider_pos = strpos($ns_name, '\\'); + + if( $divider_pos !== false ) { + + $divider_pos_last = strrpos($ns_name, '\\'); + + return [ + 'vendor' => substr($ns_name, 0, $divider_pos), + 'parts' => ($divider_pos !== $divider_pos_last) + ? explode( + '\\', + substr( + $ns_name, + ($divider_pos + 1), + $divider_pos_last - ($divider_pos + 1) + ) + ) + : [], + 'base' => substr($ns_name, ($divider_pos_last + 1)), + ]; + + } else { + + return [ + 'vendor' => $ns_name, + 'parts' => [], + 'base' => '', + ]; + } + } } diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php index cb1a3eb..8f551b3 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php index 7f69f11..2bd7f1e 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php index e9f4744..ab761c7 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php index 0289e7f..22c7a46 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php index fed90ea..c2bdb0f 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php index 392ab45..cfb50f8 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php index 1ce5d67..72304da 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php index aef187f..d979999 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php index 303bdfb..9194c22 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php @@ -11,7 +11,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php index 24de334..606aad9 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php index ace2630..dff3d66 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php index 6a74081..e548f1a 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php index aaed27c..6f36c7b 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php index d948a05..b733146 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php index 71e5aee..bb9f664 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php index 2dc7951..206ab94 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php index e472619..de985b0 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php index 1651099..1015ef8 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php index af21e05..9da4daf 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/PlacementEnum.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/PlacementEnum.php index 4c52fac..f21074d 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/PlacementEnum.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/PlacementEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Tokenizer.php b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Tokenizer.php index bbaa995..b02a91b 100644 --- a/dist/stonetable/lib/php-code-test-suite/PhpTokens/Tokenizer.php +++ b/dist/stonetable/lib/php-code-test-suite/PhpTokens/Tokenizer.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/utilities/AbstractHandler.php b/dist/stonetable/lib/php-code-test-suite/utilities/AbstractHandler.php index 3ff47db..620fb7b 100644 --- a/dist/stonetable/lib/php-code-test-suite/utilities/AbstractHandler.php +++ b/dist/stonetable/lib/php-code-test-suite/utilities/AbstractHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/utilities/ClosureHandler.php b/dist/stonetable/lib/php-code-test-suite/utilities/ClosureHandler.php index b168f56..7a6b3a8 100644 --- a/dist/stonetable/lib/php-code-test-suite/utilities/ClosureHandler.php +++ b/dist/stonetable/lib/php-code-test-suite/utilities/ClosureHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/utilities/IncludeHandler.php b/dist/stonetable/lib/php-code-test-suite/utilities/IncludeHandler.php index 7685b0c..5011680 100644 --- a/dist/stonetable/lib/php-code-test-suite/utilities/IncludeHandler.php +++ b/dist/stonetable/lib/php-code-test-suite/utilities/IncludeHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/php-code-test-suite/utilities/utilities.php b/dist/stonetable/lib/php-code-test-suite/utilities/utilities.php index d3c042f..b1215f5 100644 --- a/dist/stonetable/lib/php-code-test-suite/utilities/utilities.php +++ b/dist/stonetable/lib/php-code-test-suite/utilities/utilities.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/Autoload.php b/dist/stonetable/lib/project-directory/Autoload.php index 29c12bb..45d6b81 100644 --- a/dist/stonetable/lib/project-directory/Autoload.php +++ b/dist/stonetable/lib/project-directory/Autoload.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/BranchedTestDirectory.php b/dist/stonetable/lib/project-directory/BranchedTestDirectory.php index ff13508..97f17de 100644 --- a/dist/stonetable/lib/project-directory/BranchedTestDirectory.php +++ b/dist/stonetable/lib/project-directory/BranchedTestDirectory.php @@ -12,7 +12,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/DemoSpecialComment.php b/dist/stonetable/lib/project-directory/DemoSpecialComment.php index 20d8a41..7309644 100644 --- a/dist/stonetable/lib/project-directory/DemoSpecialComment.php +++ b/dist/stonetable/lib/project-directory/DemoSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/FileIterator.php b/dist/stonetable/lib/project-directory/FileIterator.php index 97cec01..069708e 100644 --- a/dist/stonetable/lib/project-directory/FileIterator.php +++ b/dist/stonetable/lib/project-directory/FileIterator.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/FileTrait.php b/dist/stonetable/lib/project-directory/FileTrait.php index a91cda4..e93f3c6 100644 --- a/dist/stonetable/lib/project-directory/FileTrait.php +++ b/dist/stonetable/lib/project-directory/FileTrait.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/LinkSpecialComment.php b/dist/stonetable/lib/project-directory/LinkSpecialComment.php index 330586e..192a3ca 100644 --- a/dist/stonetable/lib/project-directory/LinkSpecialComment.php +++ b/dist/stonetable/lib/project-directory/LinkSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/MainDirectoriesEnum.php b/dist/stonetable/lib/project-directory/MainDirectoriesEnum.php index 615e0c8..f58f558 100644 --- a/dist/stonetable/lib/project-directory/MainDirectoriesEnum.php +++ b/dist/stonetable/lib/project-directory/MainDirectoriesEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/PlaygroundFile.php b/dist/stonetable/lib/project-directory/PlaygroundFile.php index 28b846a..bbcb2ed 100644 --- a/dist/stonetable/lib/project-directory/PlaygroundFile.php +++ b/dist/stonetable/lib/project-directory/PlaygroundFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/ProjectDirectory.php b/dist/stonetable/lib/project-directory/ProjectDirectory.php index a0b0bc2..638bb7c 100644 --- a/dist/stonetable/lib/project-directory/ProjectDirectory.php +++ b/dist/stonetable/lib/project-directory/ProjectDirectory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/ProjectFile.php b/dist/stonetable/lib/project-directory/ProjectFile.php index a0d3478..67425a8 100644 --- a/dist/stonetable/lib/project-directory/ProjectFile.php +++ b/dist/stonetable/lib/project-directory/ProjectFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -188,7 +188,6 @@ public function replaceByCoords( } $data = ($before_portion . $replacement); - $file_size = $this->file->getSize(); if( $coords[1] < $file_size ) { @@ -400,6 +399,39 @@ public function rebuildSpecialComment( } } + /** Removes given special comment. */ + public function removeSpecialComment( + SpecialComment $special_comment + ): ?bool { + + if( $this->file->getSize() && $this->isSupportedFileType() ) { + + $coords = $this->containsSpecialComment($special_comment); + + if( !$coords ) { + return null; + } + + $this->file->rewind(); + clearstatcache(); + + while( + $this->file->fseek($coords[1]) === 0 + && ($char = $this->file->fread(1)) !== false + && ( $char === "\r" || $char === "\n" ) + ) { + $coords[1]++; + } + + return $this->replaceByCoords($coords, ''); + + // File is empty or unsupported. + } else { + + return null; + } + } + /** Rebuilds all special comments. */ public function rebuildAllSpecialCommentLines(): ?bool { @@ -422,6 +454,28 @@ public function rebuildAllSpecialCommentLines(): ?bool { } } + /** Removes all special comments. */ + public function removeAllSpecialCommentLines(): ?bool { + + if( $this->file->getSize() && $this->isSupportedFileType() ) { + + foreach( $this->special_comments as $special_comment ): + + if( $this->removeSpecialComment($special_comment) === false ) { + return false; + } + + endforeach; + + return true; + + // File is empty or unsupported. + } else { + + return null; + } + } + /** Retrieves full contents of this file. */ public function getContents(): string|false { diff --git a/dist/stonetable/lib/project-directory/ProjectFileObject.php b/dist/stonetable/lib/project-directory/ProjectFileObject.php index d7e0beb..c2d3e75 100644 --- a/dist/stonetable/lib/project-directory/ProjectFileObject.php +++ b/dist/stonetable/lib/project-directory/ProjectFileObject.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/ProjectFileObjectFactory.php b/dist/stonetable/lib/project-directory/ProjectFileObjectFactory.php index fdc7e1b..4a055b7 100644 --- a/dist/stonetable/lib/project-directory/ProjectFileObjectFactory.php +++ b/dist/stonetable/lib/project-directory/ProjectFileObjectFactory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/ProjectRootDirectory.php b/dist/stonetable/lib/project-directory/ProjectRootDirectory.php index 432cc19..9233f25 100644 --- a/dist/stonetable/lib/project-directory/ProjectRootDirectory.php +++ b/dist/stonetable/lib/project-directory/ProjectRootDirectory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/RecursiveFileIterator.php b/dist/stonetable/lib/project-directory/RecursiveFileIterator.php index 4f9336e..f347cee 100644 --- a/dist/stonetable/lib/project-directory/RecursiveFileIterator.php +++ b/dist/stonetable/lib/project-directory/RecursiveFileIterator.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/SourceFile.php b/dist/stonetable/lib/project-directory/SourceFile.php index 6926e21..8c80326 100644 --- a/dist/stonetable/lib/project-directory/SourceFile.php +++ b/dist/stonetable/lib/project-directory/SourceFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/SourceSpecialComment.php b/dist/stonetable/lib/project-directory/SourceSpecialComment.php index 71b48f4..7a10c56 100644 --- a/dist/stonetable/lib/project-directory/SourceSpecialComment.php +++ b/dist/stonetable/lib/project-directory/SourceSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/SpecialComment.php b/dist/stonetable/lib/project-directory/SpecialComment.php index 5e02ef6..0524d32 100644 --- a/dist/stonetable/lib/project-directory/SpecialComment.php +++ b/dist/stonetable/lib/project-directory/SpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/StaticFile.php b/dist/stonetable/lib/project-directory/StaticFile.php index e8b93ab..93590cb 100644 --- a/dist/stonetable/lib/project-directory/StaticFile.php +++ b/dist/stonetable/lib/project-directory/StaticFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/stonetable/lib/project-directory/StaticSpecialComment.php b/dist/stonetable/lib/project-directory/StaticSpecialComment.php index 58f6912..b125db4 100644 --- a/dist/stonetable/lib/project-directory/StaticSpecialComment.php +++ b/dist/stonetable/lib/project-directory/StaticSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.4 */ diff --git a/dist/stonetable/lib/project-directory/TestFile.php b/dist/stonetable/lib/project-directory/TestFile.php index 8147aaf..2fcbbf4 100644 --- a/dist/stonetable/lib/project-directory/TestFile.php +++ b/dist/stonetable/lib/project-directory/TestFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/dist/web/stonetable/api/directory-listing.php b/dist/web/stonetable/api/directory-listing.php index d901187..e30e81d 100644 --- a/dist/web/stonetable/api/directory-listing.php +++ b/dist/web/stonetable/api/directory-listing.php @@ -47,7 +47,6 @@ } $charset = 'UTF-8'; -$transliterator = 'Any-Latin; Latin-ASCII'; $has_search_query = ( $search_query !== null ); if( !$has_search_query ) { @@ -58,12 +57,17 @@ } else { $file_iterator = $project_file_object->getRecursiveIterator(); - + $has_transliterator = function_exists('transliterator_transliterate'); + $transliterator = 'Any-Latin; Latin-ASCII'; $comparable_search_query = mb_strtolower($search_query, $charset); - $comparable_search_query = transliterator_transliterate( - $transliterator, - $comparable_search_query - ); + + if( $has_transliterator ) { + + $comparable_search_query = transliterator_transliterate( + $transliterator, + $comparable_search_query + ); + } } $data = []; @@ -91,10 +95,13 @@ $charset ); - $comparable_searchable_str = transliterator_transliterate( - $transliterator, - $comparable_searchable_str - ); + if( $has_transliterator ) { + + $comparable_searchable_str = transliterator_transliterate( + $transliterator, + $comparable_searchable_str + ); + } if( mb_strpos( diff --git a/dist/web/stonetable/api/file-handler.php b/dist/web/stonetable/api/file-handler.php index b4dd1ae..529caa0 100644 --- a/dist/web/stonetable/api/file-handler.php +++ b/dist/web/stonetable/api/file-handler.php @@ -38,6 +38,9 @@ ); } +$force_source = get_value_exists('force_source', '0'); +$force_source = ( is_numeric($force_source) && $force_source === '1' ); + /** * Enumerates view handler names. */ @@ -46,7 +49,7 @@ enum ViewHandlersEnum: string { case OUTPUT_CODE_PARTS = 'demo-output'; } -$handler_name = ( $project_file_object instanceof TestFile ) +$handler_name = ( ($project_file_object instanceof TestFile) && !$force_source ) ? ViewHandlersEnum::OUTPUT_CODE_PARTS : ViewHandlersEnum::SOURCE_CODE_PARTS; @@ -225,7 +228,7 @@ function( string $value ) use( &$i ): string { $inner_html, $known_vendors_by_base ); - $inner_html = $formatter->convertNamespacesToHtmlLinks( + $inner_html = $formatter->formatNamespaces( $inner_html, function( string $namespace, diff --git a/dist/web/stonetable/api/projects-listing.php b/dist/web/stonetable/api/projects-listing.php index eb401cd..d3d5ec4 100644 --- a/dist/web/stonetable/api/projects-listing.php +++ b/dist/web/stonetable/api/projects-listing.php @@ -55,16 +55,17 @@ $search_query = get_value_exists('project_search_query'); $has_search_query = ( $search_query !== null ); -$search_query_limit = 100; $charset = 'UTF-8'; $transliterator = 'Any-Latin; Latin-ASCII'; if( $has_search_query ) { - $search_query = transliterator_transliterate( - $transliterator, - mb_strtolower($search_query, $charset) - ); + $search_query_limit = 100; + $has_transliterator = function_exists('transliterator_transliterate'); + $search_query_lc = mb_strtolower($search_query, $charset); + $search_query = ( $has_transliterator ) + ? transliterator_transliterate($transliterator, $search_query_lc) + : $search_query_lc; if( mb_strlen($search_query) > $search_query_limit ) { send_error( @@ -77,6 +78,10 @@ $index = 0; $select_from = (($page_number - 1) * $entries_per_page + 1); $select_to = ($select_from + $entries_per_page - 1); +$config_file_ending = (DIRECTORY_SEPARATOR + . ProjectRootDirectory::SYS_CONFIG_DIR_NAME + . DIRECTORY_SEPARATOR + . ProjectRootDirectory::SYS_CONFIG_FILE_NAME); foreach( $file_iterator as $fileinfo ) { @@ -85,20 +90,16 @@ if( $fileinfo->isDir() && !str_starts_with($file_name, '.') - && file_exists( - $fileinfo->getPathname() - . DIRECTORY_SEPARATOR - . ProjectRootDirectory::SYS_CONFIG_DIR_NAME - . DIRECTORY_SEPARATOR - . ProjectRootDirectory::SYS_CONFIG_FILE_NAME - ) + && file_exists($fileinfo->getPathname() . $config_file_ending) && ( !$has_search_query || mb_strpos( - transliterator_transliterate( - $transliterator, - mb_strtolower($file_name, $charset) - ), + ( ( $has_transliterator ) + ? transliterator_transliterate( + $transliterator, + mb_strtolower($file_name, $charset) + ) + : mb_strtolower($file_name, $charset) ), $search_query, encoding: $charset ) !== false @@ -143,7 +144,7 @@ $data[] = [ 'title' => $title, 'pathname' => '/foo/bar', - 'url' => 'https://localhost/', + 'url' => 'http://localhost/', ]; } } diff --git a/dist/web/stonetable/api/rebuild-special-comments.php b/dist/web/stonetable/api/rebuild-special-comments.php index df7d209..64af835 100644 --- a/dist/web/stonetable/api/rebuild-special-comments.php +++ b/dist/web/stonetable/api/rebuild-special-comments.php @@ -26,7 +26,6 @@ !($project_file_object instanceof SourceFile) && !($project_file_object instanceof TestFile) ) { - send_error( "File $path does not represent a source, or a test file" ); diff --git a/dist/web/stonetable/api/remove-special-comments.php b/dist/web/stonetable/api/remove-special-comments.php new file mode 100644 index 0000000..6fabd46 --- /dev/null +++ b/dist/web/stonetable/api/remove-special-comments.php @@ -0,0 +1,42 @@ +find($path); + +if( !$project_file_object ) { + send_error("File with path $path was not found"); +} + +if( + !($project_file_object instanceof SourceFile) + && !($project_file_object instanceof TestFile) +) { + send_error( + "File $path does not represent a source, or a test file" + ); +} + +$remove_result = $project_file_object->removeAllSpecialCommentLines(); + +if( $remove_result === false ) { + send_error("Could not remove special comment lines"); +} elseif( $remove_result === null ) { + send_error("There was nothing to remove"); +} else { + send_success([]); +} diff --git a/dist/web/stonetable/app/index.html b/dist/web/stonetable/app/index.html index 233a889..44fd21d 100644 --- a/dist/web/stonetable/app/index.html +++ b/dist/web/stonetable/app/index.html @@ -1 +1 @@ -Stonetable \ No newline at end of file +Stonetable \ No newline at end of file diff --git a/dist/web/stonetable/assets/css/code-message.css b/dist/web/stonetable/assets/css/code-message.css index d73b2e6..d5baeb7 100644 --- a/dist/web/stonetable/assets/css/code-message.css +++ b/dist/web/stonetable/assets/css/code-message.css @@ -1 +1 @@ -.code-msg{border:1px dashed #ccc;display:flex;flex-direction:column;gap:1em;margin:15px 0 0;padding:15px}.code-msg>*{margin:0}.code-msg :any-link{text-decoration:underline;text-decoration-color:#666;text-decoration-style:dotted;text-underline-offset:4px}.code-msg :any-link:hover{text-decoration-style:solid}.code-msg a,.code-msg code{overflow-wrap:anywhere}.code-msg code{font-family:Menlo,Monaco,Courier New,monospace;font-size:90%}.code-msg>.h{color:#666}.code-msg .arg-l{display:flex;flex-wrap:wrap;list-style-type:none;margin:0;padding:0}.code-msg .arg-l>li{counter-increment:argument-counter}.code-msg .arg-l>li:before{background-color:#eee;border-radius:5px;content:counter(argument-counter);display:inline-flex;font-size:80%;margin-right:3px;padding:1px 3px}.code-msg .arg-l>li:not(:last-child){margin-right:5px}.code-msg .arg-l>li:not(:last-child):after{content:","}.code-msg dl{column-gap:15px;display:grid;grid-template-columns:max-content 1fr;margin:0}.code-msg dl>dt{color:#666}.code-msg dl>dd{margin:0}.code-msg .stk-tr-l{list-style-type:decimal;padding-left:40px}.code-msg .stk-tr-l>li::marker{color:#666}.code-msg-err{border-color:#e42a2a}.code-msg-warn{border-color:#f48424}.code-msg-note{border-color:#ece130}.code-msg-dep{border-color:#516f79}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#001180)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#0a00ff)}.code-msg .func-name{color:var(--code-php-highlight-function,#795e27)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#0a8658)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#0531fa)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#0a8658)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#a21515)}@media (prefers-color-scheme:dark){.code-msg .arg-l>li:before{background-color:#111}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#9ddbfe)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#559cd6)}.code-msg .func-name{color:var(--code-php-highlight-function,#dcdcaa)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#ffd601)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#ce9278)}} \ No newline at end of file +:root{--pathname-base-highlight:#669321;--pathname-base-highlight-php:#9f74c4}@media (prefers-color-scheme:dark){:root{--pathname-base-highlight:#669321;--pathname-base-highlight-php:#9f74c4}}.code-msg{border:1px dashed #ccc;display:flex;flex-direction:column;gap:1em;margin:15px 0 0;padding:15px}.code-msg>*{margin:0}.code-msg :any-link{text-decoration:underline;text-decoration-color:#666;text-decoration-style:dotted;text-underline-offset:4px}.code-msg :any-link:hover{text-decoration-style:solid}.code-msg a,.code-msg code{overflow-wrap:anywhere}.code-msg code{font-family:Menlo,Monaco,Courier New,monospace;font-size:90%}.code-msg>.h{color:#666}.code-msg .arg-l{display:flex;flex-wrap:wrap;list-style-type:none;margin:0;padding:0}.code-msg .arg-l>li{counter-increment:argument-counter}.code-msg .arg-l>li:before{background-color:#eee;border-radius:5px;content:counter(argument-counter);display:inline-flex;font-size:80%;margin-right:3px;padding:1px 3px}.code-msg .arg-l>li:not(:last-child){margin-right:5px}.code-msg .arg-l>li:not(:last-child):after{content:","}.code-msg dl{column-gap:15px;display:grid;grid-template-columns:max-content 1fr;margin:0}.code-msg dl>dt{color:#666}.code-msg dl>dd{margin:0}.code-msg .err-code+dd{color:var(--code-php-highlight-number,#0a8658)}.code-msg .stk-tr-l{list-style-type:decimal;padding-left:40px}.code-msg .stk-tr-l>li::marker{color:#666}.code-msg-err{border-color:#e42a2a}.code-msg-warn{border-color:#f48424}.code-msg-note{border-color:#ece130}.code-msg-dep{border-color:#516f79}.code-msg .path .base{color:var(--pathname-base-highlight)}.code-msg .path .base.ext-php{color:var(--pathname-base-highlight-php)}.code-msg .ns-name.no-file,.code-msg .path.no-file{text-decoration:underline var(--bg-color-restrained,#666) wavy;-webkit-text-decoration:underline var(--bg-color-restrained,#666) wavy;text-decoration-thickness:1px;text-underline-offset:3px}.code-msg .cls-name,.code-msg .ns-name .base{color:var(--code-php-highlight-class-name,#257e99)}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#001180)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#0a00ff)}.code-msg .func-name,.code-msg .ns-name.closure .base,.code-msg .ns-name.func .base{color:var(--code-php-highlight-function,#795e27)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#0a8658)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#0531fa)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#0a8658)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#a21515)}@media (prefers-color-scheme:dark){.code-msg .arg-l>li:before{background-color:#111}.code-msg .err-code+dd{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .cls-name,.code-msg .ns-name .base{color:var(--code-php-highlight-class-name,#4ec9b0)}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#9ddbfe)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#559cd6)}.code-msg .func-name,.code-msg .ns-name.closure .base,.code-msg .ns-name.func .base{color:var(--code-php-highlight-function,#dcdcaa)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#ffd601)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#ce9278)}} \ No newline at end of file diff --git a/dist/web/stonetable/assets/css/output.css b/dist/web/stonetable/assets/css/output.css index 37b3124..813c6ab 100644 --- a/dist/web/stonetable/assets/css/output.css +++ b/dist/web/stonetable/assets/css/output.css @@ -1 +1 @@ -.code-msg{border:1px dashed #ccc;display:flex;flex-direction:column;gap:1em;margin:15px 0 0;padding:15px}.code-msg>*{margin:0}.code-msg :any-link{text-decoration:underline;text-decoration-color:#666;text-decoration-style:dotted;text-underline-offset:4px}.code-msg :any-link:hover{text-decoration-style:solid}.code-msg a,.code-msg code{overflow-wrap:anywhere}.code-msg code{font-family:Menlo,Monaco,Courier New,monospace;font-size:90%}.code-msg>.h{color:#666}.code-msg .arg-l{display:flex;flex-wrap:wrap;list-style-type:none;margin:0;padding:0}.code-msg .arg-l>li{counter-increment:argument-counter}.code-msg .arg-l>li:before{background-color:#eee;border-radius:5px;content:counter(argument-counter);display:inline-flex;font-size:80%;margin-right:3px;padding:1px 3px}.code-msg .arg-l>li:not(:last-child){margin-right:5px}.code-msg .arg-l>li:not(:last-child):after{content:","}.code-msg dl{column-gap:15px;display:grid;grid-template-columns:max-content 1fr;margin:0}.code-msg dl>dt{color:#666}.code-msg dl>dd{margin:0}.code-msg .stk-tr-l{list-style-type:decimal;padding-left:40px}.code-msg .stk-tr-l>li::marker{color:#666}.code-msg-err{border-color:#e42a2a}.code-msg-warn{border-color:#f48424}.code-msg-note{border-color:#ece130}.code-msg-dep{border-color:#516f79}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#001180)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#0a00ff)}.code-msg .func-name{color:var(--code-php-highlight-function,#795e27)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#0a8658)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#0531fa)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#0a8658)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#a21515)}@media (prefers-color-scheme:dark){.code-msg .arg-l>li:before{background-color:#111}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#9ddbfe)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#559cd6)}.code-msg .func-name{color:var(--code-php-highlight-function,#dcdcaa)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#ffd601)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#ce9278)}}:root{--bg-color:#fff;--text-color:#1e1e1e;--divider-color:#bbb;color-scheme:light dark}*,:after,:before{box-sizing:border-box}body,html{margin:0;padding:0}html{font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;height:100%}body{background-color:var(--bg-color);color:var(--text-color);min-height:100%;padding:52px 15px 15px}:any-link{color:inherit}.tb,.tb *{display:flex}.tb{background-color:var(--bg-color);border-bottom:1px solid var(--divider-color);color:var(--text-color);height:52px;left:0;overflow:auto hidden;padding:3px;position:fixed;right:0;scrollbar-width:thin;top:0}.tb nav{margin-left:auto}.tb nav :any-link{text-decoration:none}.tb nav ul{list-style:none;margin:0;padding:0}.tb nav li{white-space:nowrap}.tb nav a{align-items:center;border-radius:5px;height:45px;justify-content:center;padding:3px 12px;text-align:center}.tb nav a:hover{background-color:#eee}.o{border:1px dashed #666;font:13px/1.5 Menlo,Monaco,Courier New,monospace;margin:15px 0 0;padding:15px;white-space:pre-wrap}.o :any-link{text-decoration:underline;text-decoration-skip-ink:auto;text-decoration-skip-ink:all;text-decoration-style:dotted;text-underline-offset:3px}.o :any-link:hover{text-decoration-style:solid}@media (prefers-color-scheme:dark){:root{--bg-color:#1e1e1e;--text-color:#ccc;--divider-color:#111}.tb nav a:hover{background-color:#111}} \ No newline at end of file +:root{--pathname-base-highlight:#669321;--pathname-base-highlight-php:#9f74c4}@media (prefers-color-scheme:dark){:root{--pathname-base-highlight:#669321;--pathname-base-highlight-php:#9f74c4}}.code-msg{border:1px dashed #ccc;display:flex;flex-direction:column;gap:1em;margin:15px 0 0;padding:15px}.code-msg>*{margin:0}.code-msg :any-link{text-decoration:underline;text-decoration-color:#666;text-decoration-style:dotted;text-underline-offset:4px}.code-msg :any-link:hover{text-decoration-style:solid}.code-msg a,.code-msg code{overflow-wrap:anywhere}.code-msg code{font-family:Menlo,Monaco,Courier New,monospace;font-size:90%}.code-msg>.h{color:#666}.code-msg .arg-l{display:flex;flex-wrap:wrap;list-style-type:none;margin:0;padding:0}.code-msg .arg-l>li{counter-increment:argument-counter}.code-msg .arg-l>li:before{background-color:#eee;border-radius:5px;content:counter(argument-counter);display:inline-flex;font-size:80%;margin-right:3px;padding:1px 3px}.code-msg .arg-l>li:not(:last-child){margin-right:5px}.code-msg .arg-l>li:not(:last-child):after{content:","}.code-msg dl{column-gap:15px;display:grid;grid-template-columns:max-content 1fr;margin:0}.code-msg dl>dt{color:#666}.code-msg dl>dd{margin:0}.code-msg .err-code+dd{color:var(--code-php-highlight-number,#0a8658)}.code-msg .stk-tr-l{list-style-type:decimal;padding-left:40px}.code-msg .stk-tr-l>li::marker{color:#666}.code-msg-err{border-color:#e42a2a}.code-msg-warn{border-color:#f48424}.code-msg-note{border-color:#ece130}.code-msg-dep{border-color:#516f79}.code-msg .path .base{color:var(--pathname-base-highlight)}.code-msg .path .base.ext-php{color:var(--pathname-base-highlight-php)}.code-msg .ns-name.no-file,.code-msg .path.no-file{text-decoration:underline var(--bg-color-restrained,#666) wavy;-webkit-text-decoration:underline var(--bg-color-restrained,#666) wavy;text-decoration-thickness:1px;text-underline-offset:3px}.code-msg .cls-name,.code-msg .ns-name .base{color:var(--code-php-highlight-class-name,#257e99)}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#001180)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#0a00ff)}.code-msg .func-name,.code-msg .ns-name.closure .base,.code-msg .ns-name.func .base{color:var(--code-php-highlight-function,#795e27)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#0a8658)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#0531fa)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#0a8658)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#a21515)}@media (prefers-color-scheme:dark){.code-msg .arg-l>li:before{background-color:#111}.code-msg .err-code+dd{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .cls-name,.code-msg .ns-name .base{color:var(--code-php-highlight-class-name,#4ec9b0)}.code-msg .code-php .var{color:var(--code-php-highlight-variable,#9ddbfe)}.code-msg .code-php .type{color:var(--code-php-highlight-keyword,#559cd6)}.code-msg .func-name,.code-msg .ns-name.closure .base,.code-msg .ns-name.func .base{color:var(--code-php-highlight-function,#dcdcaa)}.code-msg .arg-l .float .text,.code-msg .arg-l .int .text,.code-msg .line-num{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .punc-brkt{color:var(--code-php-highlight-punctuation-level-1n,#ffd601)}.code-msg .arg-l .info{color:var(--code-php-highlight-number,#b6cda8)}.code-msg .arg-l .string .text{color:var(--code-php-highlight-string,#ce9278)}}:root{--bg-color:#fff;--text-color:#1e1e1e;--divider-color:#bbb;color-scheme:light dark}*,:after,:before{box-sizing:border-box}body,html{margin:0;padding:0}html{font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;height:100%}body{background-color:var(--bg-color);color:var(--text-color);min-height:100%;padding:52px 15px 15px}:any-link{color:inherit}.tb,.tb *{display:flex}.tb{background-color:var(--bg-color);border-bottom:1px solid var(--divider-color);color:var(--text-color);height:52px;left:0;overflow:auto hidden;padding:3px;position:fixed;right:0;scrollbar-width:thin;top:0}.tb nav{margin-left:auto}.tb nav :any-link{text-decoration:none}.tb nav ul{list-style:none;margin:0;padding:0}.tb nav li{white-space:nowrap}.tb nav a{align-items:center;border-radius:5px;height:45px;justify-content:center;padding:3px 12px;text-align:center}.tb nav a:hover{background-color:#eee}.o{border:1px dashed #666;font:13px/1.5 Menlo,Monaco,Courier New,monospace;margin:15px 0 0;padding:15px;white-space:pre-wrap}.o :any-link{text-decoration:underline;text-decoration-skip-ink:auto;text-decoration-skip-ink:all;text-decoration-style:dotted;text-underline-offset:3px}.o :any-link:hover{text-decoration-style:solid}.o>.code-msg{font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif}@media (prefers-color-scheme:dark){:root{--bg-color:#1e1e1e;--text-color:#ccc;--divider-color:#111}.tb nav a:hover{background-color:#111}} \ No newline at end of file diff --git a/dist/web/stonetable/config.php b/dist/web/stonetable/config.php index a6da743..134fee9 100644 --- a/dist/web/stonetable/config.php +++ b/dist/web/stonetable/config.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * Path name to the directory containing web projects. + * Path name to the directory containing PHP projects. * * Trailing slash should be excluded. Please normalize using `realpath()` if * required. diff --git a/dist/web/stonetable/demo-page-init.php b/dist/web/stonetable/demo-page-init.php index d6eeee2..cafddb1 100644 --- a/dist/web/stonetable/demo-page-init.php +++ b/dist/web/stonetable/demo-page-init.php @@ -393,5 +393,3 @@ function assert_true( mixed $value, string $error_message ): void { define(__NAMESPACE__ . '\ERROR_HANDLER', $dpi_error_handler); define(__NAMESPACE__ . '\DEBUGGER', $dpi_debugger); - -namespace UserDemo; diff --git a/src/lib/php-code-test-suite/Autoload.php b/src/lib/php-code-test-suite/Autoload.php index 1d77ea6..ddcaeb3 100644 --- a/src/lib/php-code-test-suite/Autoload.php +++ b/src/lib/php-code-test-suite/Autoload.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/Debugger/Debugger.php b/src/lib/php-code-test-suite/Debugger/Debugger.php index b6bc11c..825ba5a 100644 --- a/src/lib/php-code-test-suite/Debugger/Debugger.php +++ b/src/lib/php-code-test-suite/Debugger/Debugger.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -168,11 +168,11 @@ public function traceDataToCompactLine( if( $format ) { - $result .= sprintf( - '%s', - ( $trace_data['class'] - ?? $formatter->shortenPathname($filename) ) - ); + $result .= ( isset($trace_data['class']) ) + ? $formatter->formatClassNameOrNamespace($trace_data['class']) + : $formatter::formatPathnameAddWrappers( + $formatter->shortenPathname($filename) + ); } else { @@ -180,6 +180,7 @@ public function traceDataToCompactLine( } if( !isset($trace_data['class']) && $trace_data['line'] ) { + $result .= ( $format ) ? sprintf( ':%d' @@ -190,22 +191,34 @@ public function traceDataToCompactLine( } $result .= ( $trace_data['type'] ?? ' ' ); - $result .= ( $format ) - ? sprintf( - '%s' - . '(' - . ')' - . '', - $trace_data['function'] - ) - : ($trace_data['function'] . '()'); + + if( $format ) { + + $separator_pos = strrpos($trace_data['function'], '\\'); + + if( $separator_pos === false ) { + $result .= $this->formatter->formatSimplifiedFunctionStr( + $trace_data['function'] + ); + } else { + $result .= $this->formatter->formatNamespaceName( + $trace_data['function'], + ['func'] + ) . '(' + . ')'; + } + + } else { + + $result .= ($trace_data['function'] . '()'); + } if( $format && $convert_links ) { $result = $formatter->buildIdeHtmlLink( $filename, $result, - ((int)$trace_data['line'] ?? null), + ( (int)$trace_data['line'] ?? null ), class_names: ['file'] ); } @@ -225,12 +238,19 @@ class_names: ['file'] if( is_object($arg) ) { + $class = $arg::class; + $formatted_class = $formatter->formatClassNameOrNamespace( + $class + ); $argument = ( $convert_links ) - ? $formatter->namespaceToIdeHtmlLink($arg::class) - : $arg::class; + ? $formatter->namespaceToIdeHtmlLink( + $class, + text: $formatted_class + ) + : $formatted_class; if( !$argument ) { - $argument = $arg::class; + $argument = $formatted_class; } $allow_html_entities = false; @@ -238,7 +258,7 @@ class_names: ['file'] /* Don't attempt to export and show text for the following types, eg. `var_export` will fail on large arrays containing objects with circular reference, etc. */ - } elseif( is_array($arg) && is_resource($arg) ) { + } elseif( is_array($arg) || is_resource($arg) ) { $argument = ''; @@ -249,11 +269,11 @@ class_names: ['file'] // String (can be file path or namespace name). if( - str_starts_with($argument, '\'') - && str_ends_with($argument, '\'') + str_starts_with($argument, "'") + && str_ends_with($argument, "'") ) { - $trimmed_arg = trim($argument, '\''); + $trimmed_arg = trim($argument, "'"); $length = strlen($trimmed_arg); if( $formatter->isQualifiedPathname($trimmed_arg) ) { @@ -273,12 +293,23 @@ class_names: ['file'] '\\', $trimmed_arg ); + + if( $format ) { + $namespace_formatted + = $formatter->formatClassNameOrNamespace( + $namespace + ); + } + $argument = ( $convert_links ) ? $formatter->namespaceToIdeHtmlLink( $namespace, - class_names: ['file'] + class_names: ['file'], + text: $namespace_formatted ) - : $namespace; + : ( ( $format ) + ? $namespace_formatted + : $namespace ); $allow_html_entities = false; } diff --git a/src/lib/php-code-test-suite/OutputText/OutputTextFormatter.php b/src/lib/php-code-test-suite/OutputText/OutputTextFormatter.php index 4ac2819..2432b21 100644 --- a/src/lib/php-code-test-suite/OutputText/OutputTextFormatter.php +++ b/src/lib/php-code-test-suite/OutputText/OutputTextFormatter.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -18,6 +18,8 @@ namespace PCTS\OutputText; +use PCTS\PhpTokens\EnhancedPhpToken; + class OutputTextFormatter { /** Files with the following file formats will be shortened. */ @@ -123,11 +125,52 @@ public function formatPathname( return ($pathname . $text_suffix); } - $text = ($this->shortenPathname($pathname) . $text_suffix); + return $this->formatPathnameWithText( + $pathname, + $this->shortenPathname($pathname), + $text_suffix, + $line_number, + $column_number, + $class_names + ); + } + + /** + * Formats qualified/verified pathname. + * + * @param string $pathname Path name reference. + * @param string $text Text representation of the pathname. + * @param string $suffix Text suffix to add after formatted text. + * @param int|null $line_number Line number. + * @param int|null $column_number Column number. + * @param array|null $class_names When links are used, add these classes. + * @return string If HTML formatting is enabled, HTML formatted text, + * otherwise just plain text + */ + protected function formatPathnameWithText( + string $pathname, + string $text, + string $suffix = '', + ?int $line_number = null, + ?int $column_number = null, + ?array $class_names = null + ): string { + + $file_exists = file_exists($pathname); + + if( $this->format_html ) { + $path_classes = []; + if( !$file_exists ) { + $path_classes[] = 'no-file'; + } + $text = self::formatPathnameAddWrappers($text, $path_classes); + } + + $text = ($text . $suffix); $is_link = ( $this->format_html + && $file_exists && $this->convert_links - && file_exists($pathname) ); return ( $is_link ) @@ -141,6 +184,36 @@ public function formatPathname( : $text; } + /** Adds outer and inner HTML wrappers to the given pathname. */ + public static function formatPathnameAddWrappers( + string $pathname, + array $path_classes = [], + array $base_classes = [] + ): string { + + $basename = basename($pathname); + $basename_len = strlen($basename); + $extension = pathinfo($pathname, PATHINFO_EXTENSION); + $path_classes = ['path', ...$path_classes]; + $base_classes = ['base', ...$base_classes]; + + if( $extension === 'php' ) { + $base_classes[] = 'ext-php'; + } + + return sprintf( + '', + implode(' ', $path_classes) + ) + . substr($pathname, 0, -$basename_len) + . sprintf( + '%s', + implode(' ', $base_classes), + substr($pathname, -$basename_len) + ) + . ''; + } + /** Tells if the given value is recognized as a qualified namespace. */ public function isQualifiedNamespace( string $value @@ -163,10 +236,7 @@ public function format( ): string { $result = $this->shortenFilenamesAll($text); - - if( $this->convert_links ) { - $result = $this->convertNamespacesToHtmlLinks($result); - } + $result = $this->formatNamespaces($result); return $result; } @@ -190,8 +260,8 @@ public function shortenFilenamesAll( return $text; } - /** Converts all namespaces to HTML hyperlinks in the given text string. */ - public function convertNamespacesToHtmlLinks( + /** Formats all namespaces to HTML. */ + public function formatNamespaces( string $text, ?\Closure $match_handler = null ): string { @@ -205,9 +275,10 @@ public function convertNamespacesToHtmlLinks( array_keys($this->vendor_data) ); - // Mind the "preceeded by" character group. $regex_str = sprintf( - '#(\s|^|\?|\(|"|\')((%s)[A-Za-z0-9\\\\]+)#m', + // Mind the "preceeded by" character group. + // Curly brackets "{}" are used to include "{closure}" + '#(\s|^|\?|\(|"|\'|\||:|&)((%s)[A-Za-z0-9_{}\\\\]+)#m', implode('|', $vendor_names) ); @@ -219,23 +290,62 @@ public function convertNamespacesToHtmlLinks( foreach( $matches[2] as $index => $match ) { - [$namespace, $line_number] = $match; - $vendor_name = rtrim($matches[3][$index][0], '\\'); + [$ns_name, $line_number] = $match; + [$vendor_name, $ns_start_pos] = $matches[3][$index]; + $vendor_name = rtrim($vendor_name, '\\'); + $ns_name_len = strlen($ns_name); if( !$match_handler ) { - $wrapper = $this->namespaceToIdeHtmlLink($namespace); + $ns_end_pos = ($ns_start_pos + $ns_name_len + $offset); + $is_func = ( + isset($text[$ns_end_pos]) + && $text[$ns_end_pos] === '(' + ); + $is_closure = ( + !$is_func + && EnhancedPhpToken::namespaceToParts($ns_name)['base'] + === '{closure}' + ); + $ns_name_classes = ( !$is_func ) + ? [] + : ['func']; + if( !$is_func && !$is_closure ) { + $filename = $this->namespaceToFilename($ns_name); + if( !$filename || !file_exists($filename) ) { + $ns_name_classes[] = 'no-file'; + $wrapper = $ns_name; + } elseif( $this->convert_links ) { + $wrapper = self::buildIdeHtmlLink( + $filename, + $ns_name + ); + } else { + $wrapper = $ns_name; + } + } else { + $wrapper = $ns_name; + } + $wrapper = $this->formatClassNameOrNamespace( + $wrapper, + $ns_name_classes + ); + if( $is_func || $is_closure ) { + $wrapper .= '(' + . ')'; + $ns_name_len += 2; + } } else { - $wrapper = $match_handler($namespace, $vendor_name); + $wrapper = $match_handler($ns_name, $vendor_name); } $text = substr_replace( $text, $wrapper, - ((int)$match[1] + $offset), - strlen($match[0]) + ((int)$line_number + $offset), + $ns_name_len ); - $offset += (strlen($wrapper) - strlen($match[0])); + $offset += (strlen($wrapper) - $ns_name_len); } } @@ -258,8 +368,8 @@ public function shortenFilenamesByPath( // Not preceeded by "file/". '#(?editable_file_formats) ); @@ -281,41 +391,47 @@ public function shortenFilenamesByPath( . $relative_path ); $filename_length = strlen($filename); - - $is_link = ( - $this->format_html - && $this->convert_links - && file_exists($filename) + $is_on_line = ( + isset($matches[6][$index]) + && !empty($matches[6][$index][0]) + && $matches[6][$index][1] !== -1 + ); + $is_column_num = ( + isset($matches[8][$index]) + && !empty($matches[8][$index][0]) + && $matches[8][$index][1] !== -1 + ); + $replace_text = $this->formatPathnameWithText( + $filename, + $text_relative_path, + line_number: match(true) { + $is_on_line => (int)$matches[6][$index][0], + $is_column_num => (int)$matches[8][$index][0], + default => null + }, + class_names: ['file'] ); - - $replace_text = ( $is_link ) - ? self::buildIdeHtmlLink( - $filename, - $text_relative_path, - ( (int)$matches[6][$index][0] ?: null ), - class_names: ['file'] - ) - : $text_relative_path; - $text = substr_replace( $text, $replace_text, ((int)$match[1] + $offset), $filename_length ); - $offset_add = (strlen($replace_text) - $filename_length); $offset += $offset_add; // Captured line number. if( $this->format_html - && isset($matches[6][$index]) - && !empty($matches[6][$index][0]) - && $matches[6][$index][1] !== -1 + && ($is_on_line || $is_column_num) ) { - [$line_number, $line_number_pos] = $matches[6][$index]; + if( $is_on_line ) { + [$line_number, $line_number_pos] = $matches[6][$index]; + } else { + [$line_number, $line_number_pos] = $matches[8][$index]; + } + $line_number_length = strlen($line_number); $replace_text = sprintf( '%s', @@ -338,16 +454,21 @@ class_names: ['file'] /** Converts a namespace to IDE open file HTML hyperlink. */ public function namespaceToIdeHtmlLink( string $namespace, - ?array $class_names = null + ?array $class_names = null, + ?string $text = null, ): ?string { if( !$filename = $this->namespaceToFilename($namespace) ) { return null; } + if( !file_exists($filename) ) { + return null; + } + return self::buildIdeHtmlLink( $filename, - $namespace, + ( $text ?: $namespace ), class_names: $class_names ); } @@ -416,10 +537,7 @@ public function buildIdeHtmlLink( ) ) ); - $html_link .= ( $text ) - ? $text - : $filename; - + $html_link .= ( $text ?: $filename ); $html_link .= ''; return $html_link; @@ -558,7 +676,6 @@ public static function parseIdeUriFormat( 'line' => $line_number, 'column' => $column_number, ]; - $result = $mem = ''; $format_len = strlen($ide_uri_format); $curly_stack = []; @@ -683,4 +800,95 @@ public static function parseIdeUriFormat( return $result; } + + /** HTML formats given class name - either fully qualified or keyword. */ + public function formatClassNameOrNamespace( + string $string, + array $ns_name_classes = [] + ): string { + + $separator_pos = strrpos($string, '\\'); + + // Namespace + if( $separator_pos !== false ) { + return $this->formatNamespaceName($string, $ns_name_classes); + // Class name + } else { + return sprintf( + '%s', + $string + ); + } + } + + /** + * HTML formats namespace name + * + * @param string $ns_name Namespace name. + * @param array $ns_name_classes Classes to add to namespace name wrapper. + * @return string HTML formatted namespace name. + */ + public function formatNamespaceName( + string $ns_name, + array $ns_name_classes = [] + ): string { + + $separator_pos = strrpos($ns_name, '\\'); + + if( $separator_pos === false ) { + throw new \Exception( + "Namespace name must contain backward slash separator" + ); + } + + $base = substr($ns_name, ($separator_pos + 1)); + + if( $base === '{closure}' ) { + $base = self::getFormattedClosureString(); + $ns_name_classes[] = 'closure'; + } + + $ns_name_classes = ['ns-name', ...$ns_name_classes]; + + return + sprintf( + '', + implode(' ', $ns_name_classes) + ) + . substr($ns_name, 0, ($separator_pos + 1)) + . sprintf( + '%s', + $base + ) + . ''; + } + + /** Returns HTML formatted debug string for closure. */ + public static function getFormattedClosureString(): string { + + return '{' + . 'closure' + . '}'; + } + + /** HTML formats a simplified function name string. */ + public function formatSimplifiedFunctionStr( string $func_str ): string { + + if( str_ends_with($func_str, '()') ) { + $func_str = substr($func_str, -2); + } + + $func_format = '%s'; + $punc_html = '(' + . ')'; + + if( $func_str === '{closure}' ) { + $func_str = self::getFormattedClosureString(); + } + + return (sprintf( + $func_format, + $func_str + ) . $punc_html); + } } diff --git a/src/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php b/src/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php index 3c2a911..f33bd2e 100644 --- a/src/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php +++ b/src/lib/php-code-test-suite/PhpErrors/ErrorCategoryEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php b/src/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php index 776009e..25aee47 100644 --- a/src/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php +++ b/src/lib/php-code-test-suite/PhpErrors/ErrorClassEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php b/src/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php index 6067b5f..2053265 100644 --- a/src/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php +++ b/src/lib/php-code-test-suite/PhpErrors/PhpErrorHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -247,7 +247,7 @@ public function richFormatErrorMessage( ) ); $result .= '
'; - $result .= '
Location
'; + $result .= '
Location
'; $line_number_suffix = sprintf( ':%d', $line_number @@ -264,7 +264,7 @@ class_names: ['file'] if( $error_type !== null ) { - $result .= '
Type
'; + $result .= '
Type
'; $result .= sprintf( '
%s
', self::errorTypeToString($error_type) @@ -324,24 +324,27 @@ public function richFormatException( close_html_tags: false ); - $exception_namespace = $exception::class; - - $result .= '
Error Class
'; + $result .= '
Error Class
'; $result .= '
'; + $exception_class = $exception::class; + $class_formatted = $this->formatter->formatClassNameOrNamespace( + $exception_class + ); - if( $this->formatter->isQualifiedNamespace($exception_namespace) ) { + if( $this->formatter->isQualifiedNamespace($exception_class) ) { $result .= $this->formatter->namespaceToIdeHtmlLink( - $exception_namespace + $exception_class, + text: $class_formatted ); } else { - $result .= $exception_namespace; + $result .= $class_formatted; } $result .= '
'; - $result .= '
Error Code
'; + $result .= '
Error Code
'; $result .= '
'; $result .= $exception->getCode(); $result .= '
'; diff --git a/src/lib/php-code-test-suite/PhpTokens/BracketsEnum.php b/src/lib/php-code-test-suite/PhpTokens/BracketsEnum.php index bc17dee..daee8b2 100644 --- a/src/lib/php-code-test-suite/PhpTokens/BracketsEnum.php +++ b/src/lib/php-code-test-suite/PhpTokens/BracketsEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php b/src/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php index 9f6c55a..aaed0ff 100644 --- a/src/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php +++ b/src/lib/php-code-test-suite/PhpTokens/EnhancedPhpToken.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -45,6 +45,7 @@ class EnhancedPhpToken { 'noreturn', 'parent', 'self', + 'iterable', '__COMPILER_HALT_OFFSET__', ]; @@ -95,8 +96,8 @@ public function isLeveled(): bool { * @return bool True when found, and false when not found. */ public function lookAhead( - array|string $while, - array|string $until + int|array|string $while, + int|array|string $until ): bool { $key = ($this->cache_key + 1); @@ -171,25 +172,34 @@ public function isClassNameLookBehind(): bool { } $non_whitespace_tokens = [ - T_CLASS, T_NEW, T_INSTANCEOF, T_EXTENDS, T_INTERFACE, + T_IMPLEMENTS, T_TRAIT, T_ENUM, // Traits T_USE, T_INSTEADOF, - T_IMPLEMENTS, ]; - return $this->lookBehind([ + $main_look_behind = $this->lookBehind([ + T_WHITESPACE, + T_STRING, + T_CLASS, + ...$non_whitespace_tokens + ], [T_CLASS, ...$non_whitespace_tokens]); + + #review: what role does comma exactly play? + $with_comma_look_behind = $this->lookBehind([ T_WHITESPACE, ',', T_STRING, ...$non_whitespace_tokens ], $non_whitespace_tokens); + + return $main_look_behind || $with_comma_look_behind; } /** @@ -211,9 +221,11 @@ public function isNakedLookBehind( int $token_id ): bool { /** * Tells if current token might be a class name in catch clause. */ - public function isClassNameLookBehindForCatch(): bool { + public function isClassNameLookBehindForCatch( + int|string|array $is = T_STRING + ): bool { - return ( !$this->token->is(T_STRING) ) + return ( !$this->token->is($is) ) ? false : $this->lookBehind([ T_WHITESPACE, @@ -252,6 +264,10 @@ public function isClassNameLookAhead(): bool { return $this->lookAhead( [T_WHITESPACE, T_VARIABLE, '|'], [T_VARIABLE, '|'], + // Not preceeded by double colons. + ) && !$this->lookBehind( + [T_WHITESPACE, T_DOUBLE_COLON, T_PAAMAYIM_NEKUDOTAYIM], + [T_DOUBLE_COLON, T_PAAMAYIM_NEKUDOTAYIM] ); } @@ -687,10 +703,13 @@ public function getInnerHtml(): string { */ public function getNamespaceLastComponentType(): ?NUDTE { - $type = NUDTE::CLASS_LIKE; + $type = NUDTE::CONSTANT; + $identified = false; if( $context = $this->stream->getContext() ) { + $identified = true; + if( $context instanceof NamespaceUseDeclarationBuilder ) { /* If there is a block statement in front, do not mark the last @@ -706,6 +725,43 @@ public function getNamespaceLastComponentType(): ?NUDTE { // Namespace definition will be presented as generic string. $type = null; + + } else { + + $identified = false; + } + + } elseif( + /* `isFunctionLookAhead` will not work here, because it can be a + "name" class token. */ + $this->lookAhead([T_WHITESPACE, '('], '(') + && !$this->lookBehind([T_WHITESPACE, T_NEW], T_NEW) + ) { + + $type = NUDTE::FUNCTION; + $identified = true; + } + + if( !$identified ) { + + $ns_name_parts = self::namespaceToParts($this->token->text); + + if( + ($ns_name_parts['vendor'] && !$ns_name_parts['base']) + || (!$ns_name_parts['vendor'] && $ns_name_parts['base']) + || $this->lookAhead( + [T_WHITESPACE, T_DOUBLE_COLON], + T_DOUBLE_COLON + ) + || $this->lookBehind([T_WHITESPACE, T_NEW], T_NEW) + || $this->lookBehind([T_WHITESPACE, T_USE], T_USE) + || $this->isClassNameLookBehindForCatch([ + T_NAMESPACE, + T_NAME_QUALIFIED, + T_NAME_FULLY_QUALIFIED + ]) + ) { + $type = NUDTE::CLASS_LIKE; } } @@ -838,4 +894,38 @@ public static function getNamespaceInnerHtml( return $result; } + + /** Returns parts for a given namespace name. */ + public static function namespaceToParts( string $ns_name ): array { + + $divider_pos = strpos($ns_name, '\\'); + + if( $divider_pos !== false ) { + + $divider_pos_last = strrpos($ns_name, '\\'); + + return [ + 'vendor' => substr($ns_name, 0, $divider_pos), + 'parts' => ($divider_pos !== $divider_pos_last) + ? explode( + '\\', + substr( + $ns_name, + ($divider_pos + 1), + $divider_pos_last - ($divider_pos + 1) + ) + ) + : [], + 'base' => substr($ns_name, ($divider_pos_last + 1)), + ]; + + } else { + + return [ + 'vendor' => $ns_name, + 'parts' => [], + 'base' => '', + ]; + } + } } diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php index cb1a3eb..8f551b3 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php index 7f69f11..2bd7f1e 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDeclaration.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php index e9f4744..ab761c7 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php index 0289e7f..22c7a46 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php index fed90ea..c2bdb0f 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AbstractStatement.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php index 392ab45..cfb50f8 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php b/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php index 1ce5d67..72304da 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/AnonymousFunctionDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php index aef187f..d979999 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/ArrowAnonymousFunctionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php b/src/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php index 303bdfb..9194c22 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/CategoryHintInterface.php @@ -11,7 +11,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php b/src/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php index 24de334..606aad9 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/CompoundStatement.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php b/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php index ace2630..dff3d66 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php index 6a74081..e548f1a 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/FunctionDefinitionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php index aaed27c..6f36c7b 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinition.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php index d948a05..b733146 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceDefinitionBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php index 71e5aee..bb9f664 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclaration.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php index 2dc7951..206ab94 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationBuilder.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php index e472619..de985b0 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/NamespaceUseDeclarationTypeEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php b/src/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php index 1651099..1015ef8 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php +++ b/src/lib/php-code-test-suite/PhpTokens/Language/OnFinishedHookTrait.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php b/src/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php index af21e05..9da4daf 100644 --- a/src/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php +++ b/src/lib/php-code-test-suite/PhpTokens/PhpTokenCategoryEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/PlacementEnum.php b/src/lib/php-code-test-suite/PhpTokens/PlacementEnum.php index 4c52fac..f21074d 100644 --- a/src/lib/php-code-test-suite/PhpTokens/PlacementEnum.php +++ b/src/lib/php-code-test-suite/PhpTokens/PlacementEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/PhpTokens/Tokenizer.php b/src/lib/php-code-test-suite/PhpTokens/Tokenizer.php index bbaa995..b02a91b 100644 --- a/src/lib/php-code-test-suite/PhpTokens/Tokenizer.php +++ b/src/lib/php-code-test-suite/PhpTokens/Tokenizer.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/utilities/AbstractHandler.php b/src/lib/php-code-test-suite/utilities/AbstractHandler.php index 3ff47db..620fb7b 100644 --- a/src/lib/php-code-test-suite/utilities/AbstractHandler.php +++ b/src/lib/php-code-test-suite/utilities/AbstractHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/utilities/ClosureHandler.php b/src/lib/php-code-test-suite/utilities/ClosureHandler.php index b168f56..7a6b3a8 100644 --- a/src/lib/php-code-test-suite/utilities/ClosureHandler.php +++ b/src/lib/php-code-test-suite/utilities/ClosureHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/utilities/IncludeHandler.php b/src/lib/php-code-test-suite/utilities/IncludeHandler.php index 7685b0c..5011680 100644 --- a/src/lib/php-code-test-suite/utilities/IncludeHandler.php +++ b/src/lib/php-code-test-suite/utilities/IncludeHandler.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/php-code-test-suite/utilities/utilities.php b/src/lib/php-code-test-suite/utilities/utilities.php index d3c042f..b1215f5 100644 --- a/src/lib/php-code-test-suite/utilities/utilities.php +++ b/src/lib/php-code-test-suite/utilities/utilities.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/Autoload.php b/src/lib/project-directory/Autoload.php index 29c12bb..45d6b81 100644 --- a/src/lib/project-directory/Autoload.php +++ b/src/lib/project-directory/Autoload.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/BranchedTestDirectory.php b/src/lib/project-directory/BranchedTestDirectory.php index ff13508..97f17de 100644 --- a/src/lib/project-directory/BranchedTestDirectory.php +++ b/src/lib/project-directory/BranchedTestDirectory.php @@ -12,7 +12,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/DemoSpecialComment.php b/src/lib/project-directory/DemoSpecialComment.php index 20d8a41..7309644 100644 --- a/src/lib/project-directory/DemoSpecialComment.php +++ b/src/lib/project-directory/DemoSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/FileIterator.php b/src/lib/project-directory/FileIterator.php index 97cec01..069708e 100644 --- a/src/lib/project-directory/FileIterator.php +++ b/src/lib/project-directory/FileIterator.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/FileTrait.php b/src/lib/project-directory/FileTrait.php index a91cda4..e93f3c6 100644 --- a/src/lib/project-directory/FileTrait.php +++ b/src/lib/project-directory/FileTrait.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/LinkSpecialComment.php b/src/lib/project-directory/LinkSpecialComment.php index 330586e..192a3ca 100644 --- a/src/lib/project-directory/LinkSpecialComment.php +++ b/src/lib/project-directory/LinkSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/MainDirectoriesEnum.php b/src/lib/project-directory/MainDirectoriesEnum.php index 615e0c8..f58f558 100644 --- a/src/lib/project-directory/MainDirectoriesEnum.php +++ b/src/lib/project-directory/MainDirectoriesEnum.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/PlaygroundFile.php b/src/lib/project-directory/PlaygroundFile.php index 28b846a..bbcb2ed 100644 --- a/src/lib/project-directory/PlaygroundFile.php +++ b/src/lib/project-directory/PlaygroundFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/ProjectDirectory.php b/src/lib/project-directory/ProjectDirectory.php index a0b0bc2..638bb7c 100644 --- a/src/lib/project-directory/ProjectDirectory.php +++ b/src/lib/project-directory/ProjectDirectory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/ProjectFile.php b/src/lib/project-directory/ProjectFile.php index a0d3478..67425a8 100644 --- a/src/lib/project-directory/ProjectFile.php +++ b/src/lib/project-directory/ProjectFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ @@ -188,7 +188,6 @@ public function replaceByCoords( } $data = ($before_portion . $replacement); - $file_size = $this->file->getSize(); if( $coords[1] < $file_size ) { @@ -400,6 +399,39 @@ public function rebuildSpecialComment( } } + /** Removes given special comment. */ + public function removeSpecialComment( + SpecialComment $special_comment + ): ?bool { + + if( $this->file->getSize() && $this->isSupportedFileType() ) { + + $coords = $this->containsSpecialComment($special_comment); + + if( !$coords ) { + return null; + } + + $this->file->rewind(); + clearstatcache(); + + while( + $this->file->fseek($coords[1]) === 0 + && ($char = $this->file->fread(1)) !== false + && ( $char === "\r" || $char === "\n" ) + ) { + $coords[1]++; + } + + return $this->replaceByCoords($coords, ''); + + // File is empty or unsupported. + } else { + + return null; + } + } + /** Rebuilds all special comments. */ public function rebuildAllSpecialCommentLines(): ?bool { @@ -422,6 +454,28 @@ public function rebuildAllSpecialCommentLines(): ?bool { } } + /** Removes all special comments. */ + public function removeAllSpecialCommentLines(): ?bool { + + if( $this->file->getSize() && $this->isSupportedFileType() ) { + + foreach( $this->special_comments as $special_comment ): + + if( $this->removeSpecialComment($special_comment) === false ) { + return false; + } + + endforeach; + + return true; + + // File is empty or unsupported. + } else { + + return null; + } + } + /** Retrieves full contents of this file. */ public function getContents(): string|false { diff --git a/src/lib/project-directory/ProjectFileObject.php b/src/lib/project-directory/ProjectFileObject.php index d7e0beb..c2d3e75 100644 --- a/src/lib/project-directory/ProjectFileObject.php +++ b/src/lib/project-directory/ProjectFileObject.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/ProjectFileObjectFactory.php b/src/lib/project-directory/ProjectFileObjectFactory.php index fdc7e1b..4a055b7 100644 --- a/src/lib/project-directory/ProjectFileObjectFactory.php +++ b/src/lib/project-directory/ProjectFileObjectFactory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/ProjectRootDirectory.php b/src/lib/project-directory/ProjectRootDirectory.php index 432cc19..9233f25 100644 --- a/src/lib/project-directory/ProjectRootDirectory.php +++ b/src/lib/project-directory/ProjectRootDirectory.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/RecursiveFileIterator.php b/src/lib/project-directory/RecursiveFileIterator.php index 4f9336e..f347cee 100644 --- a/src/lib/project-directory/RecursiveFileIterator.php +++ b/src/lib/project-directory/RecursiveFileIterator.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/SourceFile.php b/src/lib/project-directory/SourceFile.php index 6926e21..8c80326 100644 --- a/src/lib/project-directory/SourceFile.php +++ b/src/lib/project-directory/SourceFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/SourceSpecialComment.php b/src/lib/project-directory/SourceSpecialComment.php index 71b48f4..7a10c56 100644 --- a/src/lib/project-directory/SourceSpecialComment.php +++ b/src/lib/project-directory/SourceSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/SpecialComment.php b/src/lib/project-directory/SpecialComment.php index 5e02ef6..0524d32 100644 --- a/src/lib/project-directory/SpecialComment.php +++ b/src/lib/project-directory/SpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/StaticFile.php b/src/lib/project-directory/StaticFile.php index e8b93ab..93590cb 100644 --- a/src/lib/project-directory/StaticFile.php +++ b/src/lib/project-directory/StaticFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/lib/project-directory/StaticSpecialComment.php b/src/lib/project-directory/StaticSpecialComment.php index 58f6912..b125db4 100644 --- a/src/lib/project-directory/StaticSpecialComment.php +++ b/src/lib/project-directory/StaticSpecialComment.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.4 */ diff --git a/src/lib/project-directory/TestFile.php b/src/lib/project-directory/TestFile.php index 8147aaf..2fcbbf4 100644 --- a/src/lib/project-directory/TestFile.php +++ b/src/lib/project-directory/TestFile.php @@ -10,7 +10,7 @@ * @license MIT License * @copyright Copyright (c) 2023 LWIS Technologies * (https://www.lwis.net/) - * @version 1.0.6 + * @version 1.0.7 * @since 1.0.0 */ diff --git a/src/web/api/directory-listing.php b/src/web/api/directory-listing.php index d901187..e30e81d 100644 --- a/src/web/api/directory-listing.php +++ b/src/web/api/directory-listing.php @@ -47,7 +47,6 @@ } $charset = 'UTF-8'; -$transliterator = 'Any-Latin; Latin-ASCII'; $has_search_query = ( $search_query !== null ); if( !$has_search_query ) { @@ -58,12 +57,17 @@ } else { $file_iterator = $project_file_object->getRecursiveIterator(); - + $has_transliterator = function_exists('transliterator_transliterate'); + $transliterator = 'Any-Latin; Latin-ASCII'; $comparable_search_query = mb_strtolower($search_query, $charset); - $comparable_search_query = transliterator_transliterate( - $transliterator, - $comparable_search_query - ); + + if( $has_transliterator ) { + + $comparable_search_query = transliterator_transliterate( + $transliterator, + $comparable_search_query + ); + } } $data = []; @@ -91,10 +95,13 @@ $charset ); - $comparable_searchable_str = transliterator_transliterate( - $transliterator, - $comparable_searchable_str - ); + if( $has_transliterator ) { + + $comparable_searchable_str = transliterator_transliterate( + $transliterator, + $comparable_searchable_str + ); + } if( mb_strpos( diff --git a/src/web/api/file-handler.php b/src/web/api/file-handler.php index b4dd1ae..529caa0 100644 --- a/src/web/api/file-handler.php +++ b/src/web/api/file-handler.php @@ -38,6 +38,9 @@ ); } +$force_source = get_value_exists('force_source', '0'); +$force_source = ( is_numeric($force_source) && $force_source === '1' ); + /** * Enumerates view handler names. */ @@ -46,7 +49,7 @@ enum ViewHandlersEnum: string { case OUTPUT_CODE_PARTS = 'demo-output'; } -$handler_name = ( $project_file_object instanceof TestFile ) +$handler_name = ( ($project_file_object instanceof TestFile) && !$force_source ) ? ViewHandlersEnum::OUTPUT_CODE_PARTS : ViewHandlersEnum::SOURCE_CODE_PARTS; @@ -225,7 +228,7 @@ function( string $value ) use( &$i ): string { $inner_html, $known_vendors_by_base ); - $inner_html = $formatter->convertNamespacesToHtmlLinks( + $inner_html = $formatter->formatNamespaces( $inner_html, function( string $namespace, diff --git a/src/web/api/projects-listing.php b/src/web/api/projects-listing.php index eb401cd..d3d5ec4 100644 --- a/src/web/api/projects-listing.php +++ b/src/web/api/projects-listing.php @@ -55,16 +55,17 @@ $search_query = get_value_exists('project_search_query'); $has_search_query = ( $search_query !== null ); -$search_query_limit = 100; $charset = 'UTF-8'; $transliterator = 'Any-Latin; Latin-ASCII'; if( $has_search_query ) { - $search_query = transliterator_transliterate( - $transliterator, - mb_strtolower($search_query, $charset) - ); + $search_query_limit = 100; + $has_transliterator = function_exists('transliterator_transliterate'); + $search_query_lc = mb_strtolower($search_query, $charset); + $search_query = ( $has_transliterator ) + ? transliterator_transliterate($transliterator, $search_query_lc) + : $search_query_lc; if( mb_strlen($search_query) > $search_query_limit ) { send_error( @@ -77,6 +78,10 @@ $index = 0; $select_from = (($page_number - 1) * $entries_per_page + 1); $select_to = ($select_from + $entries_per_page - 1); +$config_file_ending = (DIRECTORY_SEPARATOR + . ProjectRootDirectory::SYS_CONFIG_DIR_NAME + . DIRECTORY_SEPARATOR + . ProjectRootDirectory::SYS_CONFIG_FILE_NAME); foreach( $file_iterator as $fileinfo ) { @@ -85,20 +90,16 @@ if( $fileinfo->isDir() && !str_starts_with($file_name, '.') - && file_exists( - $fileinfo->getPathname() - . DIRECTORY_SEPARATOR - . ProjectRootDirectory::SYS_CONFIG_DIR_NAME - . DIRECTORY_SEPARATOR - . ProjectRootDirectory::SYS_CONFIG_FILE_NAME - ) + && file_exists($fileinfo->getPathname() . $config_file_ending) && ( !$has_search_query || mb_strpos( - transliterator_transliterate( - $transliterator, - mb_strtolower($file_name, $charset) - ), + ( ( $has_transliterator ) + ? transliterator_transliterate( + $transliterator, + mb_strtolower($file_name, $charset) + ) + : mb_strtolower($file_name, $charset) ), $search_query, encoding: $charset ) !== false @@ -143,7 +144,7 @@ $data[] = [ 'title' => $title, 'pathname' => '/foo/bar', - 'url' => 'https://localhost/', + 'url' => 'http://localhost/', ]; } } diff --git a/src/web/api/rebuild-special-comments.php b/src/web/api/rebuild-special-comments.php index df7d209..64af835 100644 --- a/src/web/api/rebuild-special-comments.php +++ b/src/web/api/rebuild-special-comments.php @@ -26,7 +26,6 @@ !($project_file_object instanceof SourceFile) && !($project_file_object instanceof TestFile) ) { - send_error( "File $path does not represent a source, or a test file" ); diff --git a/src/web/api/remove-special-comments.php b/src/web/api/remove-special-comments.php new file mode 100644 index 0000000..6fabd46 --- /dev/null +++ b/src/web/api/remove-special-comments.php @@ -0,0 +1,42 @@ +find($path); + +if( !$project_file_object ) { + send_error("File with path $path was not found"); +} + +if( + !($project_file_object instanceof SourceFile) + && !($project_file_object instanceof TestFile) +) { + send_error( + "File $path does not represent a source, or a test file" + ); +} + +$remove_result = $project_file_object->removeAllSpecialCommentLines(); + +if( $remove_result === false ) { + send_error("Could not remove special comment lines"); +} elseif( $remove_result === null ) { + send_error("There was nothing to remove"); +} else { + send_success([]); +} diff --git a/src/web/app/assets/css/components/accessories.css b/src/web/app/assets/css/components/accessories.css index 4f4c92b..fe0e160 100644 --- a/src/web/app/assets/css/components/accessories.css +++ b/src/web/app/assets/css/components/accessories.css @@ -14,8 +14,8 @@ .type-file, .type-dir, .i-menu, - .i-open-lo, - .i-disc-lo, + .i-std-lo-lhs, + .i-std-lo, .tgl-lo, .tgl-word-wrap-btn, .scr.welcome h1, @@ -57,10 +57,10 @@ .type-dir > :first-child::before, .type-dir > :first-child::after, .i-menu::before, - .i-open-lo::before, - .i-open-lo::after, - .i-disc-lo::before, - .i-disc-lo::after, + .i-std-lo-lhs::before, + .i-std-lo-lhs::after, + .i-std-lo::before, + .i-std-lo::after, .tgl-lo::before, .tgl-lo::after, .tgl-word-wrap-btn::before, @@ -81,7 +81,7 @@ /* Medium Length Rightwards Arrow */ .i-md-rt-arw, - .cont-btn:not(.waiting) { + .cont-btn:not(.wtng) { --icon-size: 20px; --wing-size: 10px; } @@ -98,7 +98,11 @@ } .i-md-rt-arw::after, - .cont-btn:not(.wtng)::after { + .cont-btn:not(.wtng)::after, + .i-run::before, + [data-handler="demo-output"] .tgl-view-btn::before, + .i-code::before, + [data-handler="source-code"] .tgl-view-btn::before { top: calc(50% + var(--icon-weight-half)); left: calc(50% + var(--icon-size-half) - var(--wing-size) + var(--icon-weight-half)); @@ -134,46 +138,58 @@ /* Enter & Exit Fullscreen */ :is(.i-go-fscr, .i-exit-fscr, .tgl-fscr-btn) { - --icon-size: 10px; - --icon-offset: 1px; + --wing-size: 8px; + --icon-size: 20px; + /* Calculated */ + --icon-size-max: max(calc(var(--wing-size) * 2), var(--icon-size)); } :is(.i-go-fscr, .i-exit-fscr, .tgl-fscr-btn)::before, :is(.i-go-fscr, .i-exit-fscr, .tgl-fscr-btn)::after { - width: var(--icon-size); - height: var(--icon-size); - border: solid var(--icon-weight) var(--icon-color); + top: calc(50% - var(--icon-size-half)); + left: calc(50% - var(--icon-size-half)); border-radius: var(--icon-weight-half); + background-color: var(--icon-color); } :is(.i-go-fscr, .i-exit-fscr, .tgl-fscr-btn)::before { - bottom: calc(50% + var(--icon-offset)); - left: calc(50% + var(--icon-offset)); - border-width: var(--icon-weight) var(--icon-weight) 0 0; + width: var(--wing-size); + height: var(--icon-weight); + box-shadow: var(--offset1) 0 0, + 0 var(--offset2) 0, + var(--offset1) var(--offset2) 0; } :is(.i-go-fscr, .i-exit-fscr, .tgl-fscr-btn)::after { - top: calc(50% + var(--icon-offset)); - right: calc(50% + var(--icon-offset)); - border-width: 0 0 var(--icon-weight) var(--icon-weight); + width: var(--icon-weight); + height: var(--wing-size); + box-shadow: var(--offset2) 0 0, + 0 var(--offset1) 0, + var(--offset2) var(--offset1) 0; } - .i-exit-fscr::before, - body:fullscreen .tgl-fscr-btn::before { - border-width: 0 0 var(--icon-weight) var(--icon-weight); + .i-go-fscr, + .tgl-fscr-btn { + --offset1: calc(var(--icon-size-max) - var(--wing-size)); + --offset2: calc(var(--icon-size-max) - var(--icon-weight)); } - body:-webkit-full-screen .tgl-fscr-btn::before { - border-width: 0 0 var(--icon-weight) var(--icon-weight); + .i-exit-fscr, + body:fullscreen .tgl-fscr-btn { + /* Calculated */ + --inner-wing-size: calc(var(--wing-size) - var(--icon-weight)); + --offset1: calc(var(--icon-size-max) - var(--wing-size)); + --offset2: calc(var(--offset1) - var(--inner-wing-size)); } - .i-exit-fscr::after, - body:fullscreen .tgl-fscr-btn::after { - border-width: var(--icon-weight) var(--icon-weight) 0 0; + .i-exit-fscr::before, + body:fullscreen .tgl-fscr-btn::before { + margin-top: var(--inner-wing-size); } - body:-webkit-full-screen .tgl-fscr-btn::after { - border-width: var(--icon-weight) var(--icon-weight) 0 0; + .i-exit-fscr::after, + body:fullscreen .tgl-fscr-btn::after { + margin-left: var(--inner-wing-size); } /* Search */ @@ -529,9 +545,30 @@ background-clip: content-box; } - /* Open Layout */ + /* Standard Layout */ - .i-open-lo { + .i-std-lo { + --icon-width: 20px; + --icon-height: 14px; + --stroke-size: 2px; + } + + .i-std-lo::before { + top: 50%; + left: 50%; + width: var(--icon-width); + height: var(--icon-height); + padding-top: var(--stroke-size); + transform: translate(-50%,-50%); + border-top: solid var(--stroke-size) var(--icon-color); + background-color: var(--icon-color); + background-clip: content-box; + } + + /* Standard Layout With Sidebar */ + + .i-std-lo-lhs, + .i-std-lo-rhs { --icon-width: 20px; --icon-height: 14px; --stroke-size: 2px; @@ -539,7 +576,8 @@ --stroke-size-double: calc(var(--stroke-size) * 2); } - .i-open-lo::before { + .i-std-lo-lhs::before, + .i-std-lo-rhs::before { top: 50%; left: 50%; transform: translate(-50%, calc(0px - var(--icon-height) / 2)); @@ -548,36 +586,29 @@ background-color: var(--icon-color); } - .i-open-lo::after { + .i-std-lo-lhs::after, + .i-std-lo-rhs::after { top: 50%; left: 50%; transform: translate(-50%, calc(0px - (var(--icon-height) / 2 - var(--stroke-size-double)))); width: var(--icon-width); height: calc(var(--icon-height) - var(--stroke-size-double)); - border-left: solid var(--stroke-size-double) var(--icon-color); - padding-left: var(--stroke-size); background-color: var(--icon-color); background-clip: content-box; } - /* Discrete Layout */ + /* Standard Layout With LHS Sidebar */ - .i-disc-lo { - --icon-width: 20px; - --icon-height: 14px; - --stroke-size: 2px; + .i-std-lo-lhs::after { + border-left: solid var(--stroke-size-double) var(--icon-color); + padding-left: var(--stroke-size); } - .i-disc-lo::before { - top: 50%; - left: 50%; - width: var(--icon-width); - height: var(--icon-height); - padding-top: var(--stroke-size); - transform: translate(-50%,-50%); - border-top: solid var(--stroke-size) var(--icon-color); - background-color: var(--icon-color); - background-clip: content-box; + /* Standard Layout With RHS Sidebar */ + + .i-std-lo-rhs::after { + border-right: solid var(--stroke-size-double) var(--icon-color); + padding-right: var(--stroke-size); } /* No Word Wrap */ @@ -722,6 +753,60 @@ content: 'i'; } + /* Run */ + + .i-run, + [data-handler="demo-output"] .tgl-view-btn { + --icon-width: 25px; + --icon-height: 20px; + --line-size: 15px; + --wing-size: 10px; + /* Calculated */ + --icon-height-half: calc(var(--icon-height) / 2); + } + + .i-run::before, + [data-handler="demo-output"] .tgl-view-btn::before { + left: calc(50% - var(--icon-width) / 2); + } + + .i-run::after, + [data-handler="demo-output"] .tgl-view-btn::after { + top: calc(50% + (var(--icon-height-half) - var(--icon-weight))); + left: calc(50% + (var(--icon-width) / 2 - var(--line-size))); + width: var(--line-size); + height: var(--icon-weight); + background-color: var(--icon-color); + border-radius: var(--icon-weight-half); + } + + /* Code */ + + .i-code, + [data-handler="source-code"] .tgl-view-btn { + --wing-size: 10px; + } + + .i-code::before, + [data-handler="source-code"] .tgl-view-btn::before { + top: 50%; + left: calc(50% - 11px); + border-width: 2px 0 0 2px; + transform: rotate(-45deg); + transform-origin: 0 0; + } + + .i-code::after, + [data-handler="source-code"] .tgl-view-btn::after { + top: calc(50% - 10px); + left: calc(50% - var(--icon-weight-half) + 5px); + width: var(--icon-weight); + height: 20px; + background-color: var(--icon-color); + border-radius: var(--icon-weight-half); + transform: rotate(30deg); + } + /* Compact Buttons */ diff --git a/src/web/app/assets/css/components/app-code-message.css b/src/web/app/assets/css/components/app-code-message.css index 49588a8..e53d3d3 100644 --- a/src/web/app/assets/css/components/app-code-message.css +++ b/src/web/app/assets/css/components/app-code-message.css @@ -1,5 +1,41 @@ @import "../../../../assets/css/code-message.css"; +/* Code Message */ + +.code-msg { + padding: 20px 12px; + border-width: 1px 0; +} + +.code-msg .code-msg { + margin-top: 1em; + border-width: 1px; +} + +.code-msg .arg-l > li::before { + background-color: var(--mg-color); +} + +.code-msg .stk-tr-l > li::marker { + color: var(--bg-color-restrained); +} + +:root[data-theme="light"] .code-msg .path .base { + color: #669321; +} + +:root[data-theme="dark"] .code-msg .path .base { + color: #669321; +} + +:root[data-theme="light"] .code-msg .path .base.ext-php { + color: #9f74c4; +} + +:root[data-theme="dark"] .code-msg .path .base.ext-php { + color: #9f74c4; +} + /* Output */ .o { @@ -22,22 +58,8 @@ text-decoration-style: solid; } -/* Code Message */ - -.code-msg { - padding: 20px 12px; - border-width: 1px 0; -} - -.code-msg .code-msg { - margin-top: 1em; - border-width: 1px; -} - -.code-msg .arg-l > li::before { - background-color: var(--mg-color); -} - -.code-msg .stk-tr-l > li::marker { - color: var(--bg-color-restrained); +.o > .code-msg { + font: 16px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', + sans-serif; } \ No newline at end of file diff --git a/src/web/app/assets/css/components/code-php-highlight.css b/src/web/app/assets/css/components/code-php-highlight.css index f2fdcc7..6a6d1c7 100644 --- a/src/web/app/assets/css/components/code-php-highlight.css +++ b/src/web/app/assets/css/components/code-php-highlight.css @@ -235,7 +235,8 @@ /* Issues */ /* Namespace that is not backed by a file */ -.code-php .namespace.no-file { +.code-php .namespace.no-file, +.code-php .class-name.no-file { text-decoration: underline var(--bg-color-restrained, #666) wavy; -webkit-text-decoration: underline var(--bg-color-restrained, #666) wavy; text-decoration-skip-ink: auto; diff --git a/src/web/app/assets/scripts/app.js b/src/web/app/assets/scripts/app.js index b0c2970..261914f 100644 --- a/src/web/app/assets/scripts/app.js +++ b/src/web/app/assets/scripts/app.js @@ -205,7 +205,7 @@ function markSubstringsInString( } return stringWrap( - string, + string.normalize('NFC'), positions, searchString.length, before, @@ -244,6 +244,20 @@ function writeToClipboard(text, onSuccess, onFailure) { }); } +/** + * Checks if the currently focused element is an active form control. + * @returns {boolean} True if the active element is an input, textarea, or + * select; otherwise, false. + */ +function isActiveFormControl() { + return document.activeElement !== null + && ( + document.activeElement instanceof HTMLInputElement + || document.activeElement instanceof HTMLTextAreaElement + || document.activeElement instanceof HTMLSelectElement + ); +} + /** * Resets the app title in the document */ @@ -981,12 +995,20 @@ function SearchableApiListing( }); }); this.listingBody.addEventListener('scroll', () => { - if (this.hasMorePages() && this.hasReachedScrollThreshold()) { + if ( + // Ignore scroll when awaiting previous response + !this.scrollOccupied + && this.hasMorePages() + && this.hasReachedScrollThreshold() + ) { + this.scrollOccupied = true; this.nextPageRequest().then(payload => { if (payload) { this.appendGroupContents(payload); this.populateStateData(payload); } + }).finally(() => { + this.scrollOccupied = false; }); } }); @@ -998,9 +1020,12 @@ Object.assign(SearchableApiListing.prototype, { ? new URL(endpointUrl) : endpointUrl; }, - async fillUpContents() { - if (this.getRemainingSpace()) { + async fillUpContents(onPayload, willReplace = false) { + if (willReplace || this.getRemainingSpace()) { return this.nextPageRequestUntil(payload => { + if (typeof onPayload === 'function') { + onPayload(payload); + } this.populateStateData(payload); this.appendGroupContents(payload); return this.hasMorePages() && this.getRemainingSpace(); @@ -1130,13 +1155,15 @@ Object.assign(SearchableApiListing.prototype, { }); }, async nextPageRequestUntil(untilHandler) { - return this.request({ - pageNumber: (this.pageNumber + 1) - }).then(async payload => { - if (payload !== false && untilHandler(payload)) { - await this.nextPageRequestUntil(untilHandler); - } - }); + if (this.pageNumber === 0 || this.hasMorePages()) { + return this.request({ + pageNumber: (this.pageNumber + 1) + }).then(async payload => { + if (payload !== false && untilHandler(payload)) { + await this.nextPageRequestUntil(untilHandler); + } + }); + } }, bindSearchInput() { this.searchInput.addEventListener('input', () => { @@ -1152,7 +1179,9 @@ Object.assign(SearchableApiListing.prototype, { if (data.length) { this.populateStateData(payload); this.replaceGroupContents(payload); - this.fillUpContents(); + if (payload.maxPages > payload.pageNumber) { + this.fillUpContents(); + } // No results. } else { this.flushGroupContents(); @@ -1197,9 +1226,12 @@ Object.assign(SearchableApiListing.prototype, { })); } this.setEndpointUrl(endpointUrl); - this.flushGroupContents(); this.pageNumber = 0; - return this.fillUpContents(); + return this.fillUpContents(payload => { + if (payload && payload.pageNumber == '1') { + this.flushGroupContents(); + } + }, true); } }); @@ -1923,6 +1955,7 @@ const genericScreen = { 'main', 'project_search_query', 'file_search_query', + 'force_source', ], menuItems: [ { @@ -1991,6 +2024,7 @@ const genericScreen = { }, ], abortControllers: new Set(), + keyboardShortcuts: {}, /** * Amends the location to contain given state parameters * @param {object} params - State parameters @@ -2094,26 +2128,6 @@ const genericScreen = { onClose(callback) { this.onCloseCallbacks.add(callback); }, - /** - * Closes currently active screen - * @returns {null|boolean} Null when there is nothing to be closed - */ - close() { - if (!this.isLoaded) { - return null; - } - console.log(`closing ${this.name} screen`); - this.clearAbortControllers(); - this.container.remove(); - document.body.removeAttribute('data-current-screen-name'); - this.isLoaded = false; - if (this.onCloseCallbacks.size) { - this.onCloseCallbacks.forEach(callback => { - callback(); - }); - } - return true; - }, /** * Adds the screen container to the document body and makes it globally * available @@ -2133,6 +2147,38 @@ const genericScreen = { finishLoading() { this.isLoaded = true; currentLoadedScreen = this; + const keyboardShortcuts = { + ...genericScreen.keyboardShortcuts, + ...this.keyboardShortcuts + }; + for (const [name, method] of Object.entries(keyboardShortcuts)) { + this.keyboardShortcuts[name] = method.bind(this); + document.addEventListener('keydown', this.keyboardShortcuts[name]); + } + }, + /** + * Closes currently active screen + * @returns {null|boolean} Null when there is nothing to be closed + */ + close() { + if (!this.isLoaded) { + return null; + } + console.log(`closing ${this.name} screen`); + this.clearAbortControllers(); + this.container.remove(); + document.body.removeAttribute('data-current-screen-name'); + this.isLoaded = false; + if (this.onCloseCallbacks.size) { + this.onCloseCallbacks.forEach(callback => { + callback(); + }); + } + // Cleanup keyboard shortcut bindings + for( const [, method] of Object.entries(this.keyboardShortcuts) ) { + document.removeEventListener('keydown', method); + } + return true; }, /** * Excavates a document fragment from the corresponding screen template @@ -2493,6 +2539,17 @@ const managerScreen = { } ], onMainPanelCloseCallbacks: new Set(), + lastMainPanelSendParams: {}, + keyboardShortcuts: { + 'reload': function(e) { + // R key (no meta) + if (!e.metaKey && (e.key === 'r' || e.key === 'R')) { + if (this.currentMainPath && !isActiveFormControl()) { + this.reloadMainPanel(); + } + } + } + }, /** * Runs all tasks required to load the screen * @param {object} params - Params to use when loading @@ -2571,7 +2628,7 @@ const managerScreen = { this.listingGroup.prepend(item); } }, - (searchField) => { + searchField => { if (searchField.value !== '') { let params = {}; params[searchField.name] = searchField.value; @@ -2590,7 +2647,9 @@ const managerScreen = { document.body.dataset.layout = 'discrete'; } else if (layout === 'discrete') { document.body.dataset.layout = 'open'; - this.listing.fillUpContents(); + if (isCompact.matches) { + this.listing.fillUpContents(); + } } }); } @@ -2628,7 +2687,9 @@ const managerScreen = { document.body.dataset.layout = 'discrete'; } else { document.body.dataset.layout = 'open'; - this.listing.fillUpContents(); + if (isCompact.matches) { + this.listing.fillUpContents(); + } } // Project not found. } else if (payload !== false && !payload.data) { @@ -2711,17 +2772,23 @@ const managerScreen = { * @param {string} path - File's path name * @param {bool} setParams - Whether to set path name in location */ - loadIntoMainPanel(path, setParams = true) { + loadIntoMainPanel(path, setParams = true, sendParams = {}) { if ( this.mainPanelAbortController && !this.mainPanelAbortController.signal.aborted ) { this.mainPanelAbortController.abort(); } - this.removeMainPanelMasterMessage(); - this.truncateMainPanel(); - this.mainPanel.removeAttribute('data-handler'); + const loadCleanUp = () => { + this.removeMainPanelMasterMessage(); + this.truncateMainPanel(); + if (this.lastMainPanelSendParams) { + this.releaseParams(Object.keys(this.lastMainPanelSendParams)); + } + this.mainPanel.removeAttribute('data-handler'); + }; const waitingTimeout = setTimeout(() => { + loadCleanUp(); this.mainPanel.classList.add('wtng'); }, 150); if (isCompact.matches) { @@ -2744,9 +2811,13 @@ const managerScreen = { this.loadedProjectData.pathname ); } + for (const [key, val] of Object.entries(sendParams)) { + url.searchParams.set(key, val); + } this.mainPanelAbortController = this.provideAbortController(); apiRequest(url, this.mainPanelAbortController).then(payload => { if (payload !== false) { + loadCleanUp(); const data = payload.data; const mainPanelToolbar = createElement('div', { classes: ['tb'], @@ -2788,12 +2859,16 @@ const managerScreen = { data.meta.handlerName ); if (setParams) { - this.setParams({ + const mainParams = { main: path, - }); + }; + this.setParams({...mainParams, ...sendParams}); + this.lastMainPanelSendParams = sendParams; } this.currentMainPath = path; } else { + this.currentMainPath = null; + this.truncateMainPanel(); this.putOnNoFileMessage(); this.releaseParams(['main'], 'replace'); } @@ -3048,7 +3123,7 @@ const managerScreen = { }); const currentButton = createElement('button', { text: fileData.basename, - title: "Reload file", + title: "Reload file (R)", }); currentButton.addEventListener('click', () => { this.reloadMainPanel(); @@ -3076,7 +3151,7 @@ const managerScreen = { const reloadButton = createElement('button', { classes: ['rld-btn'], text: "Reload", - title: "Reload file", + title: "Reload file (R)", }); reloadButton.addEventListener('click', () => { this.reloadMainPanel(); @@ -3103,6 +3178,26 @@ const managerScreen = { }); menu.append(wordWrapButton); } + if (fileData.category === 'demo' || fileData.category === 'unit') { + const toggleView = createElement('button', { + classes: ['tgl-view-btn'], + text: "Toggle view", + title: "Toggle view", + }); + toggleView.addEventListener('click', () => { + if (!Object.hasOwn(stateObj, 'force_source')) { + this.loadIntoMainPanel(this.currentMainPath, true, { + 'force_source': '1', + }); + } else { + this.loadIntoMainPanel(this.currentMainPath); + this.releaseParams([ + 'force_source', + ]); + } + }); + menu.append(toggleView); + } menu.append(reloadButton, closeButton); return menu; }, @@ -3111,16 +3206,23 @@ const managerScreen = { */ reloadMainPanel() { if (this.currentMainPath) { - this.loadIntoMainPanel(this.currentMainPath); + this.loadIntoMainPanel( + this.currentMainPath, + true, + this.lastMainPanelSendParams + ); } }, /** * Closes main panel */ closeMainPanel() { + this.currentMainPath = null; this.mainPanel.innerHTML = ''; this.putOnNoFileMessage(); - this.releaseParams(['main']); + this.releaseParams( + ['main', ...Object.keys(this.lastMainPanelSendParams)] + ); if (this.onMainPanelCloseCallbacks.size) { this.onMainPanelCloseCallbacks.forEach(callback => { callback(); @@ -3863,9 +3965,8 @@ const shortNotifications = { function ShortNotification(text, timeout) { const container = this.createElement(); container.innerText = text; - this.container = shortNotifications.container.appendChild( - container - ); + shortNotifications.container.prepend(container); + this.container = shortNotifications.container.firstElementChild; this.timeoutHandlerId = setTimeout(() => { this.close(); }, timeout); diff --git a/src/web/app/index.html b/src/web/app/index.html index 9510cbc..c8a3f2c 100644 --- a/src/web/app/index.html +++ b/src/web/app/index.html @@ -6,7 +6,7 @@ - + diff --git a/src/web/app/tpls/icons.html b/src/web/app/tpls/icons.html index b0a71e8..7f826d2 100644 --- a/src/web/app/tpls/icons.html +++ b/src/web/app/tpls/icons.html @@ -72,9 +72,11 @@

CSS Icons

-
+
-
+
+ +
@@ -84,6 +86,10 @@

CSS Icons

+
+ +
+ diff --git a/src/web/assets/css/code-message.css b/src/web/assets/css/code-message.css index 8013433..4cbc840 100644 --- a/src/web/assets/css/code-message.css +++ b/src/web/assets/css/code-message.css @@ -1,3 +1,15 @@ +:root { + --pathname-base-highlight: #669321; + --pathname-base-highlight-php: #9f74c4; +} + +@media (prefers-color-scheme: dark) { + :root { + --pathname-base-highlight: #669321; + --pathname-base-highlight-php: #9f74c4; + } +} + /* Code Message */ .code-msg { @@ -87,6 +99,10 @@ margin: 0; } +.code-msg .err-code + dd { + color: var(--code-php-highlight-number, #0a8658); +} + /* Stack Trace List */ .code-msg .stk-tr-l { @@ -118,6 +134,28 @@ /* Highlighting */ +.code-msg .path .base { + color: var(--pathname-base-highlight); +} + +.code-msg .path .base.ext-php { + color: var(--pathname-base-highlight-php); +} + +.code-msg .path.no-file, +.code-msg .ns-name.no-file { + text-decoration: underline var(--bg-color-restrained, #666) wavy; + -webkit-text-decoration: underline var(--bg-color-restrained, #666) wavy; + /* Safari does not support this inside shorthand */ + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} + +.code-msg .cls-name, +.code-msg .ns-name .base { + color: var(--code-php-highlight-class-name, #257e99); +} + .code-msg .code-php .var { color: var(--code-php-highlight-variable, #001180); } @@ -126,7 +164,9 @@ color: var(--code-php-highlight-keyword, #0a00ff); } -.code-msg .func-name { +.code-msg .func-name, +.code-msg .ns-name.func .base, +.code-msg .ns-name.closure .base { color: var(--code-php-highlight-function, #795e27); } @@ -156,8 +196,19 @@ background-color: #111; } + /* Metadata */ + + .code-msg .err-code + dd { + color: var(--code-php-highlight-number, #b6cda8); + } + /* Highlighting */ + .code-msg .cls-name, + .code-msg .ns-name .base { + color: var(--code-php-highlight-class-name, #4ec9b0); + } + .code-msg .code-php .var { color: var(--code-php-highlight-variable, #9ddbfe); } @@ -166,7 +217,9 @@ color: var(--code-php-highlight-keyword, #559cd6); } - .code-msg .func-name { + .code-msg .func-name, + .code-msg .ns-name.func .base, + .code-msg .ns-name.closure .base { color: var(--code-php-highlight-function, #dcdcaa); } diff --git a/src/web/assets/css/output.css b/src/web/assets/css/output.css index 0d339cf..7a176a0 100644 --- a/src/web/assets/css/output.css +++ b/src/web/assets/css/output.css @@ -109,6 +109,12 @@ body { text-decoration-style: solid; } +.o > .code-msg { + font: 16px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', + sans-serif; +} + @media (prefers-color-scheme: dark) { :root { diff --git a/src/web/config.php b/src/web/config.php index a6da743..134fee9 100644 --- a/src/web/config.php +++ b/src/web/config.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * Path name to the directory containing web projects. + * Path name to the directory containing PHP projects. * * Trailing slash should be excluded. Please normalize using `realpath()` if * required. diff --git a/src/web/demo-page-init.php b/src/web/demo-page-init.php index d6eeee2..cafddb1 100644 --- a/src/web/demo-page-init.php +++ b/src/web/demo-page-init.php @@ -393,5 +393,3 @@ function assert_true( mixed $value, string $error_message ): void { define(__NAMESPACE__ . '\ERROR_HANDLER', $dpi_error_handler); define(__NAMESPACE__ . '\DEBUGGER', $dpi_debugger); - -namespace UserDemo; diff --git a/src/web/doc/arbitrary-abbreviations.txt b/src/web/doc/arbitrary-abbreviations.txt index b23a4af..0547d50 100644 --- a/src/web/doc/arbitrary-abbreviations.txt +++ b/src/web/doc/arbitrary-abbreviations.txt @@ -7,6 +7,7 @@ body - bd breadcrumbs - brcr button - btn category - cat +class - cls close - cl collapse - coll color - clr @@ -35,7 +36,9 @@ light - lt lines - lns list - l listing - lst +location - loc message - msg +namespace - ns notification - notif number - num option - opt diff --git a/src/web/tpls/error-message.html b/src/web/tpls/error-message.html index cb99307..bf3a900 100644 --- a/src/web/tpls/error-message.html +++ b/src/web/tpls/error-message.html @@ -36,7 +36,7 @@

Stack trace list:

  1. - .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:30 B() + .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:30 B()
    1. object(#24) stdClass
    2. string(36) "/Users/JohnDoe/Documents/..."
    3. @@ -45,7 +45,7 @@
  2. - .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:40 A() + .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:40 A()
    1. string(12) "Hello World!"
    2. int(3) 100
    3. @@ -69,7 +69,7 @@

      Stack trace list:

      1. - .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:30 B() + .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:30 B()
        1. object(#24) stdClass
        2. string(36) "/Users/JohnDoe/Documents/..."
        3. @@ -78,7 +78,7 @@
      2. - .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:40 A() + .../php-code-test-suite/test/demo/static/PhpErrors/simulation-nested-errors.php:40 A()
        1. string(12) "Hello World!"
        2. int(3) 100
        3. diff --git a/test/projects/test-project-1/src/syntax-highlighting.php b/test/projects/test-project-1/src/syntax-highlighting.php index cce69d3..e7a790b 100644 --- a/test/projects/test-project-1/src/syntax-highlighting.php +++ b/test/projects/test-project-1/src/syntax-highlighting.php @@ -35,6 +35,12 @@ $hello = "World"; echo $$var1; +\me(); +Me::class; +new Hello\World(); +Demo\SRC_PATH; +function &test(...$args): string|array|ParentClass|\Closure {} + $var2 = ((((1 + 2)))); const CONST_2 = ME; diff --git a/test/projects/test-project-1/test/demo/static/Rectangle.php b/test/projects/test-project-1/test/demo/static/Rectangle.php index 5cfcbd2..36a6d3f 100644 --- a/test/projects/test-project-1/test/demo/static/Rectangle.php +++ b/test/projects/test-project-1/test/demo/static/Rectangle.php @@ -8,7 +8,7 @@ /*** Demo Code ***/ -require_once (__DIR__ . '/../../../src/Rectangle.php'); +require_once (Demo\SRC_PATH . '/Rectangle.php'); echo "Constructing Rectangle(5,10)...", PHP_EOL; $rectangleA = new Rectangle(5,10); diff --git a/test/projects/test-project-1/test/demo/static/hello-world.php b/test/projects/test-project-1/test/demo/static/hello-world.php index 15d962d..3ec19c0 100644 --- a/test/projects/test-project-1/test/demo/static/hello-world.php +++ b/test/projects/test-project-1/test/demo/static/hello-world.php @@ -8,7 +8,7 @@ /*** Demo Code ***/ -require_once (__DIR__ . '/../../../src/hello-world.php'); +require_once (Demo\SRC_PATH . '/hello-world.php'); echo helloWorld(), PHP_EOL; diff --git a/test/projects/test-project-1/test/demo/static/output-errors-test.php b/test/projects/test-project-1/test/demo/static/output-errors-test.php index b7d8052..b21645d 100644 --- a/test/projects/test-project-1/test/demo/static/output-errors-test.php +++ b/test/projects/test-project-1/test/demo/static/output-errors-test.php @@ -9,11 +9,11 @@ /*** Demo Code ***/ echo "Normal output 1"; -trigger_error("Error", E_USER_ERROR); +trigger_error("Deprecated", E_USER_DEPRECATED); echo "Normal output 2"; -trigger_error("Warning", E_USER_WARNING); -echo "Normal output 3"; trigger_error("Notice", E_USER_NOTICE); +echo "Normal output 3"; +trigger_error("Warning", E_USER_WARNING); echo "Normal output 4"; -trigger_error("Deprecated", E_USER_DEPRECATED); +trigger_error("Error", E_USER_ERROR); echo "Normal output 5"; diff --git a/test/projects/test-project-1/test/demo/static/tests.php b/test/projects/test-project-1/test/demo/static/tests.php new file mode 100644 index 0000000..fb0f8c3 --- /dev/null +++ b/test/projects/test-project-1/test/demo/static/tests.php @@ -0,0 +1,61 @@ +