Redaktilo 1.3 06/11/2014
TL;DR: Redaktilo is a library which wraps array manipulation to make it feel like using a text editor.
Six months ago, I talked about a silly library I was working on.
I've just released it's version 1.3, so I figured that maybe it's time to talk about it as the mature and usefull project it has become.
Statistics
First, here's some meaningless figures:
- fisrt commit: at 08:06:46, on the 24th thursday of April 2014
- number of releases: 36 (including 11 stable ones)
- number of contributors: 3 (Loick Piera, WouterJ and myself)
- lines of code (according to Insight, for version 1.3.0): 1 183
History
In my two previous pet projects (GnugatWizardBundle and Fossil), as well as in professional projects, I've encountered the need to manipulate lines (from a file or a static string).
I've done 3 different implementations, each less reusable than the other, so I started to think that there was something to do here.
That's how Redaktilo is born!
Public API
My purpose was to create a single service which would be used as a text editor ("redaktilo" means "editor", in esperanto):
<?php
namespace Gnugat\Redaktilo;
class Editor
{
// Filesystem operations:
public function open($filename, $force = false);
public function save(File $file);
// Line selection
public function jumpAbove(Text $text, $pattern, $location = null);
public function jumpBelow(Text $text, $pattern, $location = null);
// Line detection
public function hasAbove(Text $text, $pattern, $location = null);
public function hasBelow(Text $text, $pattern, $location = null);
// Line manipulations
public function insertAbove(Text $text, $addition, $location = null);
public function insertBelow(Text $text, $addition, $location = null);
public function replace(Text $text, $replacement, $location = null);
public function replaceAll(Text $text, $pattern, $replacement);
public function remove(Text $text, $location = null);
// You can execute custom commands!
public function run($name, array $input);
}
This service is stateless, it manipulates the following model:
<?php
namespace Gnugat\Redaktilo;
class Text
{
public function getLines();
public function setLines(array $lines);
public function getLength();
public function getLineBreak();
public function setLineBreak($lineBreak);
public function getCurrentLineNumber();
public function setCurrentLineNumber($lineNumber);
public function getLine($lineNumber = null);
public function setLine($line, $lineNumber = null);
}
Note: The
File
model extendsText
and addsfilename
getter and setter.
As you can see, everything is centered around a current line, but specifying
directly a line number is possible (that's the meaning of the $location
argument).
Facade and extension points
To be honest, Editor
doesn't do anything, it just wraps some low level
services. Amongst those, we have:
SearchEngine
: decides whichSearchStrategy
will be usedCommandInvoker
: executes aCommand
Those two are actually here to provide extension points: if you need to look for
a line with something else than a regular expression, you can create your own
SearchStrategy
, register it in SearchEngine
and it will be available
directly from the Editor
!
If the manipulations provided out of the box aren't sufficient, you can create
your own Command
, register it in CommandInvoker
and it will be available
directly from the Editor
!
Commands rely on user input, which is why Loïck worked on InputSanitizer
to
validate it. If the ones provided aren't enough, you can still create your own
implementations.
Finally, I'd like to highlight Wouter's work on the EditorFatory
helper: it is
really cumbersome to instantiate manually Editor
... But thanks to this
factory, you'll never have to do it by yourself!
Note: Working on a Symfony2 project? You can use RedaktiloBundle, which also provides tags to register custom search strategies and commands.
What's next?
Loïck is currently improving the library's exceptions for the version 1.4.
For version 1.5, two new methods will be added to Text
:
incrementCurrentLineNumber
and decrementCurrentLineNumber
, to avoid the
following:
<?php
require __DIR__.'/vendor/autoload.php';
use Gnugat\Redaktilo\EditorFactory;
$editor = EditorFactory::createEditor();
$file = $editor->open('/tmp/monty-python.txt');
// Currently
$currentLineNumber = $file->getCurrentLineNumber();
$file->setCurrentLineNumber($currentLineNumber + 2);
// Soon...
$file->incrementCurrentLineNumber(2);
For the final version 1.6, a strong documentation of the deprecations will be done, leading the way to version 2.0 where those will be removed (50% of the code base will vanish!).
Note: As I'm using Redaktilo everyday, I might discover new improvements to be done, leading the given version numbers above to change.
Frequently Asked Questions
Is it a GUI / CLI tool?
A question I've been often asked, because describing Redaktilo as a text editor might be a bit misleading. It is a library which feels like an editor, but it is in no way an actual editor you might run.
Here's an example of what you might be doing currently without Redaktilo:
<?php
$lines = file('/tmp/monty-python.txt');
$currentLineNumber = 42;
$section = array_slice($lines, 0, $current, true); // Lines from 0 to 42
$reversedSection = array_reverse($section, true);
$found = preg_grep('/a knewt/', $reversedSection); // finding the first occurence, above line 42
$currentLineNumber = key($found);
array_splice($lines, $currentLineNumber + 1, 0, 'new line below "a knewt"');
$content = implode("\n", $lines); // Let's hope it wasn't a file created on Windows.
file_put_contents($content, '/tmp/monty-python');
With redaktilo:
<?php
require __DIR__.'/vendor/autoload.php';
use Gnugat\Redaktilo\EditorFactory;
$editor = EditorFactory::createEditor();
$file = $editor->open('/tmp/monty-python');
$editor->jumpAbove($file, '/a knewt/', 42);
$editor->insertBelow($file, 'new line below "a knewt"');
$editor->save($file);
Is it a code editor?
Because the code example on the README is about inserting a new line in the
AppKernel
file of a Symfony2 application, I also get this question.
Redaktilo can edit any text file, so it includes source files. But keep in mind that it only manipulates lines, when you might want to manipulate an AST to edit code.
I'm working on a new silly project: Medio. It heavily relies on Redaktilo to actually edit code: so you can make a code editor with it, but again before you start ask yourself if an AST wouldn't be better.
Conclusion
Redaktilo is a library which makes line manipulation dead easy! It provides extension points and will soon reach version 2 which will mark its final maturity point.
Until then, you can still use it safely, it's been stable for 11 releases now.