Browse Source

Merge pull request #14261 from cakephp/editor-link

Add methods to support editor links
Mark Story 6 years ago
parent
commit
21b14eddb3
3 changed files with 145 additions and 0 deletions
  1. 4 0
      phpstan-baseline.neon
  2. 77 0
      src/Error/Debugger.php
  3. 64 0
      tests/TestCase/Error/DebuggerTest.php

+ 4 - 0
phpstan-baseline.neon

@@ -765,3 +765,7 @@ parameters:
 			count: 1
 			path: src/basics.php
 
+		-
+			message: "#^Result of \\&\\& is always false.$#"
+			count: 1
+			path: src/Error/Debugger.php

+ 77 - 0
src/Error/Debugger.php

@@ -34,6 +34,7 @@ use Cake\Log\Log;
 use Cake\Utility\Hash;
 use Cake\Utility\Security;
 use Cake\Utility\Text;
+use Closure;
 use Exception;
 use InvalidArgumentException;
 use ReflectionObject;
@@ -61,6 +62,7 @@ class Debugger
     protected $_defaultConfig = [
         'outputMask' => [],
         'exportFormatter' => null,
+        'editor' => 'phpstorm',
     ];
 
     /**
@@ -108,6 +110,21 @@ class Debugger
     ];
 
     /**
+     * A map of editors to their link templates.
+     *
+     * @var array
+     */
+    protected $editors = [
+        'atom' => 'atom://core/open/file?filename={file}&line={line}',
+        'emacs' => 'emacs://open?url=file://{file}&line={line}',
+        'macvim' => 'mvim://open/?url=file://{file}&line={line}',
+        'phpstorm' => 'phpstorm://open?file={file}&line={line}',
+        'sublime' => 'subl://open?url=file://{file}&line={line}',
+        'textmate' => 'txmt://open?url=file://{file}&line={line}',
+        'vscode' => 'vscode://file/{file}:{line}',
+    ];
+
+    /**
      * Holds current output data when outputFormat is false.
      *
      * @var array
@@ -241,6 +258,66 @@ class Debugger
     }
 
     /**
+     * Add an editor link format
+     *
+     * Template strings can use the `{file}` and `{line}` placeholders.
+     * Closures templates must return a string, and accept two parameters:
+     * The file and line.
+     *
+     * @param string $name The name of the editor.
+     * @param string|\Closure $template The string template or closure
+     * @return void
+     */
+    public static function addEditor(string $name, $template): void
+    {
+        $instance = static::getInstance();
+        if (!is_string($template) && !($template instanceof Closure)) {
+            $type = getTypeName($template);
+            throw new RuntimeException("Invalid editor type of `{$type}`. Expected string or Closure.");
+        }
+        $instance->editors[$name] = $template;
+    }
+
+    /**
+     * Choose the editor link style you want to use.
+     *
+     * @param string $name The editor name.
+     * @return void
+     */
+    public static function setEditor(string $name): void
+    {
+        $instance = static::getInstance();
+        if (!isset($instance->editors[$name])) {
+            $known = implode(', ', array_keys($instance->editors));
+            throw new RuntimeException("Unknown editor `{$name}`. Known editors are {$known}");
+        }
+        $instance->setConfig('editor', $name);
+    }
+
+    /**
+     * Get a formatted URL for the active editor.
+     *
+     * @param string $file The file to create a link for.
+     * @param int $line The line number to create a link for.
+     * @return string The formatted URL.
+     */
+    public static function editorUrl(string $file, int $line): string
+    {
+        $instance = static::getInstance();
+        $editor = $instance->getConfig('editor');
+        if (!isset($instance->editors[$editor])) {
+            throw new RuntimeException("Cannot format editor URL `{$editor}` is not a known editor.");
+        }
+
+        $template = $instance->editors[$editor];
+        if (is_string($template)) {
+            return str_replace(['{file}', '{line}'], [$file, $line], $template);
+        }
+
+        return $template($file, $line);
+    }
+
+    /**
      * Recursively formats and outputs the contents of the supplied variable.
      *
      * @param mixed $var The variable to dump.

+ 64 - 0
tests/TestCase/Error/DebuggerTest.php

@@ -21,6 +21,7 @@ use Cake\Core\Configure;
 use Cake\Error\Debugger;
 use Cake\Log\Log;
 use Cake\TestSuite\TestCase;
+use RuntimeException;
 use stdClass;
 use TestApp\Error\TestDebugger;
 use TestApp\Error\Thing\DebuggableThing;
@@ -777,4 +778,67 @@ EXPECTED;
             $output
         );
     }
+
+    /**
+     * test adding invalid editor
+     *
+     * @return void
+     */
+    public function testAddEditorInvalid()
+    {
+        $this->expectException(RuntimeException::class);
+        Debugger::addEditor('nope', ['invalid']);
+    }
+
+    /**
+     * test choosing an unknown editor
+     *
+     * @return void
+     */
+    public function testSetEditorInvalid()
+    {
+        $this->expectException(RuntimeException::class);
+        Debugger::setEditor('nope');
+    }
+
+    /**
+     * test choosing a default editor
+     *
+     * @return void
+     */
+    public function testSetEditorPredefined()
+    {
+        Debugger::setEditor('phpstorm');
+        Debugger::setEditor('macvim');
+        Debugger::setEditor('sublime');
+        Debugger::setEditor('emacs');
+        // No exceptions raised.
+        $this->assertTrue(true);
+    }
+
+    /**
+     * test using a valid editor.
+     *
+     * @return void
+     */
+    public function testEditorUrlValid()
+    {
+        Debugger::addEditor('open', 'open://{file}:{line}');
+        Debugger::setEditor('open');
+        $this->assertSame('open://test.php:123', Debugger::editorUrl('test.php', 123));
+    }
+
+    /**
+     * test using a valid editor.
+     *
+     * @return void
+     */
+    public function testEditorUrlClosure()
+    {
+        Debugger::addEditor('open', function (string $file, int $line) {
+            return "${file}/${line}";
+        });
+        Debugger::setEditor('open');
+        $this->assertSame('test.php/123', Debugger::editorUrl('test.php', 123));
+    }
 }