Using int was a mistake. This patch changes String, StringImpl,
StringView and StringBuilder to use size_t instead of int for lengths.
Obviously a lot of code needs to change as a result of this.
This patch adds InsertTextCommand and RemoveTextCommand.
These two commands are used to ... insert and remove text :^)
The bulk of the logic is moved into GTextDocument, and we now use the
command's redo() virtual to perform the action. Or in other words, when
you type into the text editor, we create an InsertTextCommand, push it
onto the undo stack, and call redo() on it immediately. That's how the
text gets inserted.
This makes it quite easy to implement more commands, as there is no
distinction between a redo() and the initial application.
This works for C++ syntax highlighted text documents by caching the C++
token type in a new "arbitrary data" member of GTextDocumentSpan.
When the cursor is placed immediately before a '{' or immediately after
a '}', we highlight both of these brace buddies by changing their
corresponding spans to have a different background color.
..and spans can also now have a custom background color. :^)
You can now register a GWidget subclass with REGISTER_GWIDGET(class)
and it will be available for factory construction through the new
GWidgetClassRegistration interface.
To obtain a GWidgetClassRegistration for a given class name, you call
GWidgetClassRegistration::find(class_name). You can also iterate over
all the registered classes using GWCR::for_each(callback).
This will be very useful for implementing a proper GUI designer, and
also in the future for things like script bindings.
NOTE: All of the registrations are done in GWidget.cpp at the moment
since I ran into trouble with the fricken linker pruning the global
constructors this mechanism relies on. :^)
You can now press Ctrl+Shift+Up/Down in a GTextEditor and the currently
selected line(s) will all move together one step up/down.
If there is no selection, we move the line with the cursor on it. :^)
Since on_change handlers can alter the text document we're working on,
we have to make sure they've been run before we try looking at spans.
This fixes some flakiness when a paint happened before HackStudio had
a chance to re-highlight some C++ while editing it.
The design where clients of GTextEditor perform syntax highlighting in
the "arbitrary code execution" on_change callback is not very good.
We should find a way to move highlighting closer to the editor.
With this patch, you can now assign the same GTextDocument to multiple
GTextEditor widgets via GTextEditor::set_document().
The editors have independent cursors and selection, but all changes
are shared, and immediately propagate to all editors.
This is very unoptimized and will do lots of unnecessary invalidation,
especially line re-wrapping and repainting over and over again.
This patch decouples GTextDocument and GTextDocumentLine from the line
wrapping functionality of GTextEditor.
This should basically make it possible to have multiple GTextEditors
editing the same GTextDocument. Of course, that will require a bit more
work since there's no paint invalidation yet.
The idea here is to decouple the document from the editor widget so you
could have multiple editors being views onto the same document.
This doesn't work yet, since the document and editor are coupled in
various ways still (including a per-line back-pointer to the editor.)
This makes double-clicking on a C++ token in HackStudio select the
whole token, which is pretty nice. It's not perfect in all cases,
but a lot nicer than just expanding until we hit whitespace. :^)
This makes the backspace erase backwards until the next soft tab stop.
We currently always use 4 as the soft tab width, but I suppose we could
make it configurable at some point. :^)
It's now possible to give GTextEditor a vector of Span objects.
Spans currently tell the editor which color to use for each character
in the span. This can be used to implement syntax highlighting :^)
There were various little mistakes in the width calculations used by
the line-wrapping layout code.
With this patch, we should no longer see the horizontal scrollbar get
enabled with line-wrapping enabled. I will hide the scrollbar in a
separate patch.
text_position_at() was returning -1 if the position wasn't in
the bounds of a visual line. Now if the position is past the last
line, we simply return the last line index instead of -1.
Fixes#502.
When we update our content size, the width & height is now calculated
from the visual line rect size. Also now after we recompute all visual
lines, if the total height is different, we re-update the content size.
Compute the final file size and ftruncate() the destination file to the
right size immediately instead of incrementally appending to it.
This kind of optimization belongs in the kernel, but until we have it
there, this makes saving text files a whole lot faster. :^)