Currently, LibGUI modifies the Ctrl+Alt+Space key event to instead
represent the emoji that was selected through EmojiInputDialog. This is
limited to a single code point.
For multiple code point emoji support, individual widgets now set a hook
to be notified of the emoji selection with a UTF-8 encoded string. This
replaces the previous set_accepts_emoji_input() method.
Noticed that mouse-overing the ruler area in the TextEditor
does not change the cursor to the default cursor, instead, the
beam cursor is used, which does not look nice.
This PR extends the mousemove event and introduces a new
set_editing_cursor() function that takes care of setting the
cursor for the editor area.
This allows lines moved by Ctrl+Shift+[Up, Down] to be registered as a
command, i.e. cancellable by Ctrl+Z.
This patch also introduces the usage of TextDocument::[take,
insert]_line. Those functions forward changes to the visual lines and
then avoid some data mismatch.
Co-authored-by: Jorropo <jorropo.pgm@gmail.com>
If selected text is less than a whole line, usual delete/replace takes
place. Otherwise, if the selected text is a whole line or spans
multiple lines, the selection will be indented.
This is the only Widget that ran its callback in deferred_invoke(). It
seems to be a holdover from when syntax-highlighting ran whenever the
text changed, but that has not been true since
bec2b3086c. Running the callback
immediately has no obvious downsides, but does make it a lot easier to
reason about. (I might have spent an hour confused as to why things
were happening in the wrong order...)
This adds a search API to TextEditor.
The API that is similar to "find_text" of TextDocument (which is used
internally to do the search).
All search results (as well as the current one) are highlighted with
a "span collection", which is pretty neat :^)
TextDocument::set_spans() now also takes a "span collection index"
argument.
TextDocument keeps a map between a span collection index and its spans.
It merges the spans from all collections into a single set of spans
whenever set_spans() is called.
This allows us to style a document with multiple layers of spans, where
as previously we only supported a single layer of spans that was set
from the SyntaxHighlighter.
Fonts now provide their preferred line height based on maximum
height and requested line gap. TTFs provide a preferred line gap
from table metrics while BitmapFonts are hardcoded at the previous
default for now.
Having the delete key handling be done via an action limits our ability
to support key modifiers (e.g. ctrl+delete deleting the word in front of
the cursor).
The fact that it was an action _did_ allow us to have a delete button in
the TextEditor UI. However, this is an odd choice in the first place
that isn't common in other text editors, so I just removed it.
Moving the cursor to a different location, by any means, should
dismiss the autocomplete popup. This is the behavior of virtually
every editor/IDE out there, and it is really annoying (and
confusing) when our autocomplete doesn't behave like that.
Previously if there were no suggestions, we simply wouldn't show the
autocomplete popup at all. This is functional, but when there are no
resultes it does leave the user wondering if it actually worked.
Now, if the user requests autocomplete and we do have requests, it
behaves exactly as before, but if there' aren't any we now show a box
with the message "No suggestions" to show the user that we got the
request, there just isn't anything to suggest.
This is a helpful option to prevent unwanted side effects, distinguish
between user and programmatic input, etc. Sliders and SpinBoxes were
implementing it idiosyncratically, so let's generalize the API and
give Buttons and TextEditors the same ability.
This allows the address bar to "select all" when initially gaining focus
as Firefox and Chrome do. A future improvement on this would be for the
Widget class to mange and provide focus transition as part of the events
instead of the UrlBox class. Currently focus is updated before the event
is provided to the UrlBox class.
This ensures that the user can't copy/cut text from password boxes which
would reveal the password. It also makes sure that the undo/redo actions
stay disabled because it's difficult to reason about what these do
exactly without being able to see the result.
Anyone who inherits from `GUI::Clipboard::ClipboardClient` will receive
clipboard notifications via `clipboard_content_did_change()`.
Update ClipboardHistoryModel, TextEditor and TerminalWidget to inherit
from this class.
While under insert mode, Ctrl-U deletes all characters between the first
non-blank character of the line and the cursor.
Implement delete_from_line_start_to_cursor() in TextEditor. Then, call
the method in VimEditingEngine via its pointer to an instance of
TextEditor.
In Vim, Ctrl-H is effectively equivalent to backspace in insert mode, as
it deletes the previous character.
This commit implements method delete_previous_char() to TextEditor.
delete_char() already exists in EditingEngine, but it deletes the
next character rather than the previous. delete_previous_char() is then
called from within VimEditingEngine.
In Vim's insert mode, Ctrl-W deletes the word before the cursor, like
Ctrl-Backspace. Unlike Ctrl-Backspace, if only whitespace exists between
the end of the word and the cursor, the word will be deleted with the
whitespace.
To do so, this commit introduces two methods: delete_previous_word() for
TextEditor and first_word_before() for TextDocument, where the former
depends on the latter. delete_previous_word() is then called in
VimEditingEngine.
Making use of the new FileSystemAccessServer we are able to use
unveil without restricting our ability to open and save files.
A file argument will be unveiled automatically however all other files
require user action via the FileSystemAccessServer to gain access.
This patch adds the member variable m_substitution_code_point to
GUI::TextEditor. If non-zero, all gylphs to be drawn will be substituted
with the specified code point. This is mainly needed to support a
PasswordBox.
While the primary use-case is for single-line editors, multi-line
editors are also supported.
To prevent repeated String construction, a m_substitution_string_data
members has been added, which is an OwnPtr<Vector<u32>>. This is used as
a UTF-32 string builder. The substitution_code_point_view method uses
that Vector to provide a Utf32View of the specified length.
If something happens in response to on_change that causes the widget
to get unparented, creating a GUI::Painter will fail since it can't
find the window to paint into.
Since painting only cares about the syntax highlighting spans, what we
really want is to ensure that spans are up-to-date before we start
painting.
The problem was that rehighlighting and the on_change hook were bundled
together in an awkward lazy update mechanism. This patch fixes that by
decoupling rehighlighting and on_change. Rehighlighting is now lazy
and only happens when we handle either paint or mouse events. :^)
Fixes#8302.
Gutter -- a space left of the text, before the ruler -- is not a part of
the ruler, nor should it be treated as such. This commit implements
gutter handling in LibGUI::TextEditor as part of mild cleaning up of the
gutter handling (breakpoint icons) in HackStudio's Editor.
This commit also enables separate theming of the gutter.
This adds support for shift+return key combo in single line TextEditor
fields. Used in this case for searching backwards/forwards in the
Terminal find window.
This moves the calculation of selected words that was originally
in the TextEditor application to TextEditor in LibGUI.
This allows all applications with text editors to get
this number without having to calculating it themselves.
Renamed the virtual from "on_edit_action" to "will_execute" so it
doesn't clash with our convention for Function hook names.
Also tighten the parameter type to GUI::TextDocumentUndoCommand
since that's the only kind of command it will receive.
This was quite unreliable before. Changes to the undo stack's modified
state are now reflected in the document's modified state, and the
GUI::TextEditor widget has its undo/redo actions updated automatically.
UndoStack is still a bit hard to understand due to the lazy coalescing
of commands, and that's something we should improve upon (e.g with more
explicit, incremental command merging.) But for now, this is a nice
improvement and undo/redo finally behaves in a way that feels natural.
Have TextDocument listen for state changes on the internal undo stack,
and forward those to all clients via a new virtual function.
This simplifies updating the can_undo / can_redo states of TextEditor.