2020-01-18 05:38:21 -03:00
/*
2021-04-09 11:34:51 -03:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2022-02-10 16:28:48 -03:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2021-05-01 13:26:44 -03:00
# include "MainWidget.h"
2019-07-13 21:58:04 -03:00
# include <AK/Optional.h>
2019-07-11 15:52:33 -03:00
# include <AK/StringBuilder.h>
2019-12-19 16:20:20 -03:00
# include <AK/URL.h>
2020-12-22 21:12:27 -03:00
# include <Applications/TextEditor/TextEditorWindowGML.h>
2023-03-07 17:51:48 -03:00
# include <LibCMake/CMakeCache/SyntaxHighlighter.h>
2023-02-28 11:32:27 -03:00
# include <LibCMake/SyntaxHighlighter.h>
2021-08-25 18:56:50 -03:00
# include <LibConfig/Client.h>
2022-07-18 16:03:11 -03:00
# include <LibCore/Debounce.h>
2021-02-07 10:40:36 -03:00
# include <LibCpp/SyntaxHighlighter.h>
2020-08-11 10:13:07 -03:00
# include <LibDesktop/Launcher.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/Action.h>
# include <LibGUI/BoxLayout.h>
# include <LibGUI/Button.h>
2021-02-21 21:01:26 -03:00
# include <LibGUI/CheckBox.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/FilePicker.h>
2020-12-30 14:04:55 -03:00
# include <LibGUI/FontPicker.h>
2022-02-02 14:11:29 -03:00
# include <LibGUI/GML/SyntaxHighlighter.h>
2022-01-18 00:39:48 -03:00
# include <LibGUI/GitCommitSyntaxHighlighter.h>
2021-02-21 21:01:26 -03:00
# include <LibGUI/GroupBox.h>
2020-04-30 19:57:06 -03:00
# include <LibGUI/INISyntaxHighlighter.h>
2020-02-14 21:56:30 -03:00
# include <LibGUI/Menu.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Menubar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/MessageBox.h>
2021-01-02 07:59:55 -03:00
# include <LibGUI/RegularEditingEngine.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Statusbar.h>
2020-02-06 16:33:02 -03:00
# include <LibGUI/TextBox.h>
# include <LibGUI/TextEditor.h>
2021-04-13 11:18:20 -03:00
# include <LibGUI/Toolbar.h>
# include <LibGUI/ToolbarContainer.h>
2021-01-02 07:59:55 -03:00
# include <LibGUI/VimEditingEngine.h>
2022-04-09 04:28:38 -03:00
# include <LibGfx/Font/Font.h>
2021-02-07 12:56:02 -03:00
# include <LibJS/SyntaxHighlighter.h>
2020-04-28 16:42:45 -03:00
# include <LibMarkdown/Document.h>
2023-04-27 07:52:01 -03:00
# include <LibMarkdown/SyntaxHighlighter.h>
2021-06-21 11:57:44 -03:00
# include <LibSQL/AST/SyntaxHighlighter.h>
2021-10-21 17:45:24 -03:00
# include <LibWeb/CSS/SyntaxHighlighter/SyntaxHighlighter.h>
2021-05-20 15:47:30 -03:00
# include <LibWeb/HTML/SyntaxHighlighter/SyntaxHighlighter.h>
2022-04-30 05:46:33 -03:00
# include <LibWebView/OutOfProcessWebView.h>
2021-02-07 13:07:33 -03:00
# include <Shell/SyntaxHighlighter.h>
2019-07-11 15:52:33 -03:00
2021-05-01 13:26:44 -03:00
namespace TextEditor {
MainWidget : : MainWidget ( )
2019-07-11 15:52:33 -03:00
{
2023-01-07 09:38:23 -03:00
load_from_gml ( text_editor_window_gml ) . release_value_but_fixme_should_propagate_errors ( ) ;
2019-07-11 15:52:33 -03:00
2021-04-13 11:18:20 -03:00
m_toolbar = * find_descendant_of_type_named < GUI : : Toolbar > ( " toolbar " ) ;
m_toolbar_container = * find_descendant_of_type_named < GUI : : ToolbarContainer > ( " toolbar_container " ) ;
2020-04-28 16:42:45 -03:00
2021-01-01 04:57:48 -03:00
m_editor = * find_descendant_of_type_named < GUI : : TextEditor > ( " editor " ) ;
2019-07-11 15:52:33 -03:00
m_editor - > set_ruler_visible ( true ) ;
m_editor - > set_automatic_indentation_enabled ( true ) ;
2021-12-08 19:28:12 -03:00
if ( m_editor - > editing_engine ( ) - > is_regular ( ) )
m_editor - > set_editing_engine ( make < GUI : : RegularEditingEngine > ( ) ) ;
else if ( m_editor - > editing_engine ( ) - > is_vim ( ) )
m_editor - > set_editing_engine ( make < GUI : : VimEditingEngine > ( ) ) ;
else
VERIFY_NOT_REACHED ( ) ;
2019-08-21 16:30:20 -03:00
2022-10-23 17:16:43 -03:00
auto font_entry = Config : : read_string ( " TextEditor " sv , " Text " sv , " Font " sv , " default " sv ) ;
if ( font_entry ! = " default " )
m_editor - > set_font ( Gfx : : FontDatabase : : the ( ) . get_by_name ( font_entry ) ) ;
2023-06-14 10:54:46 -03:00
m_editor - > on_change = Core : : debounce ( 100 , [ this ] {
2020-07-04 16:19:01 -03:00
update_preview ( ) ;
2023-06-14 10:54:46 -03:00
} ) ;
2021-05-08 08:40:33 -03:00
m_editor - > on_modified_change = [ this ] ( bool modified ) {
window ( ) - > set_modified ( modified ) ;
2019-08-27 15:18:19 -03:00
} ;
2021-02-21 21:01:26 -03:00
m_find_replace_widget = * find_descendant_of_type_named < GUI : : GroupBox > ( " find_replace_widget " ) ;
2021-01-01 04:57:48 -03:00
m_find_widget = * find_descendant_of_type_named < GUI : : Widget > ( " find_widget " ) ;
m_replace_widget = * find_descendant_of_type_named < GUI : : Widget > ( " replace_widget " ) ;
2020-01-11 15:52:47 -03:00
2021-02-21 21:01:26 -03:00
m_find_textbox = * find_descendant_of_type_named < GUI : : TextBox > ( " find_textbox " ) ;
2022-07-11 14:32:29 -03:00
m_find_textbox - > set_placeholder ( " Find " sv ) ;
2019-08-21 16:30:20 -03:00
2021-02-21 21:01:26 -03:00
m_replace_textbox = * find_descendant_of_type_named < GUI : : TextBox > ( " replace_textbox " ) ;
2022-07-11 14:32:29 -03:00
m_replace_textbox - > set_placeholder ( " Replace " sv ) ;
2020-04-23 15:29:38 -03:00
2021-02-21 21:01:26 -03:00
m_match_case_checkbox = * find_descendant_of_type_named < GUI : : CheckBox > ( " match_case_checkbox " ) ;
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 15:34:31 -03:00
m_match_case_checkbox - > on_checked = [ this ] ( auto is_checked ) {
m_match_case = is_checked ;
2021-02-21 21:01:26 -03:00
} ;
m_match_case_checkbox - > set_checked ( true ) ;
2020-04-23 15:29:38 -03:00
2021-02-21 21:01:26 -03:00
m_regex_checkbox = * find_descendant_of_type_named < GUI : : CheckBox > ( " regex_checkbox " ) ;
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 15:34:31 -03:00
m_regex_checkbox - > on_checked = [ this ] ( auto is_checked ) {
m_use_regex = is_checked ;
2021-02-21 21:01:26 -03:00
} ;
m_regex_checkbox - > set_checked ( false ) ;
2020-01-11 15:52:47 -03:00
2021-02-21 21:01:26 -03:00
m_wrap_around_checkbox = * find_descendant_of_type_named < GUI : : CheckBox > ( " wrap_around_checkbox " ) ;
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 15:34:31 -03:00
m_wrap_around_checkbox - > on_checked = [ this ] ( auto is_checked ) {
m_should_wrap = is_checked ;
2021-02-21 21:01:26 -03:00
} ;
m_wrap_around_checkbox - > set_checked ( true ) ;
2020-04-23 15:29:38 -03:00
2023-01-20 16:06:05 -03:00
m_find_next_action = GUI : : Action : : create ( " Find &Next " , { Mod_Ctrl , Key_G } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find-next.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ this ] ( auto & ) {
2022-08-15 15:22:12 -03:00
find_text ( GUI : : TextEditor : : SearchDirection : : Forward , ShowMessageIfNoResults : : Yes ) ;
2019-08-25 16:35:58 -03:00
} ) ;
2023-01-20 16:06:05 -03:00
m_find_previous_action = GUI : : Action : : create ( " Find Pr&evious " , { Mod_Ctrl | Mod_Shift , Key_G } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find-previous.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ this ] ( auto & ) {
2022-08-15 15:22:12 -03:00
find_text ( GUI : : TextEditor : : SearchDirection : : Backward , ShowMessageIfNoResults : : Yes ) ;
2020-01-11 15:52:47 -03:00
} ) ;
2021-05-21 13:51:06 -03:00
m_replace_action = GUI : : Action : : create ( " Rep&lace " , { Mod_Ctrl , Key_F1 } , [ & ] ( auto & ) {
2020-01-11 15:52:47 -03:00
auto needle = m_find_textbox - > text ( ) ;
auto substitute = m_replace_textbox - > text ( ) ;
if ( needle . is_empty ( ) )
return ;
2021-02-21 21:01:26 -03:00
if ( m_use_regex )
2020-04-23 15:29:38 -03:00
m_editor - > document ( ) . update_regex_matches ( needle ) ;
2021-02-21 21:01:26 -03:00
auto found_range = m_editor - > document ( ) . find_next ( needle , m_editor - > normalized_selection ( ) . start ( ) , m_should_wrap ? GUI : : TextDocument : : SearchShouldWrap : : Yes : GUI : : TextDocument : : SearchShouldWrap : : No , m_use_regex , m_match_case ) ;
2020-01-11 15:52:47 -03:00
if ( found_range . is_valid ( ) ) {
m_editor - > set_selection ( found_range ) ;
m_editor - > insert_at_cursor_or_replace_selection ( substitute ) ;
} else {
2020-07-15 23:45:11 -03:00
GUI : : MessageBox : : show ( window ( ) ,
2022-12-04 15:02:33 -03:00
DeprecatedString : : formatted ( " Not found: \" {} \" " , needle ) ,
2022-07-11 14:32:29 -03:00
" Not found " sv ,
2020-07-15 23:45:11 -03:00
GUI : : MessageBox : : Type : : Information ) ;
2020-01-11 15:52:47 -03:00
}
} ) ;
2021-04-09 11:34:51 -03:00
m_replace_all_action = GUI : : Action : : create ( " Replace &All " , { Mod_Ctrl , Key_F2 } , [ & ] ( auto & ) {
2020-01-11 15:52:47 -03:00
auto needle = m_find_textbox - > text ( ) ;
auto substitute = m_replace_textbox - > text ( ) ;
2021-11-06 00:47:53 -03:00
auto length_delta = substitute . length ( ) - needle . length ( ) ;
2020-01-11 15:52:47 -03:00
if ( needle . is_empty ( ) )
return ;
2021-02-21 21:01:26 -03:00
if ( m_use_regex )
2020-04-23 15:29:38 -03:00
m_editor - > document ( ) . update_regex_matches ( needle ) ;
2020-01-11 15:52:47 -03:00
2021-11-06 00:47:53 -03:00
auto found_range = m_editor - > document ( ) . find_next ( needle , { } , GUI : : TextDocument : : SearchShouldWrap : : No , m_use_regex , m_match_case ) ;
2022-08-14 22:26:23 -03:00
if ( found_range . is_valid ( ) ) {
while ( found_range . is_valid ( ) ) {
m_editor - > set_selection ( found_range ) ;
m_editor - > insert_at_cursor_or_replace_selection ( substitute ) ;
auto next_start = GUI : : TextPosition ( found_range . end ( ) . line ( ) , found_range . end ( ) . column ( ) + length_delta ) ;
found_range = m_editor - > document ( ) . find_next ( needle , next_start , GUI : : TextDocument : : SearchShouldWrap : : No , m_use_regex , m_match_case ) ;
}
} else {
GUI : : MessageBox : : show ( window ( ) ,
2022-12-04 15:02:33 -03:00
DeprecatedString : : formatted ( " Not found: \" {} \" " , needle ) ,
2022-08-14 22:26:23 -03:00
" Not found " sv ,
GUI : : MessageBox : : Type : : Information ) ;
2020-01-11 15:52:47 -03:00
}
} ) ;
2021-01-01 04:57:48 -03:00
m_find_previous_button = * find_descendant_of_type_named < GUI : : Button > ( " find_previous_button " ) ;
2019-08-25 16:35:58 -03:00
m_find_previous_button - > set_action ( * m_find_previous_action ) ;
2023-01-20 16:06:05 -03:00
m_find_previous_button - > set_icon ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find-previous.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2019-08-25 16:35:58 -03:00
2021-01-01 04:57:48 -03:00
m_find_next_button = * find_descendant_of_type_named < GUI : : Button > ( " find_next_button " ) ;
2019-08-25 16:35:58 -03:00
m_find_next_button - > set_action ( * m_find_next_action ) ;
2023-01-20 16:06:05 -03:00
m_find_next_button - > set_icon ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find-next.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2019-08-21 16:30:20 -03:00
2019-08-22 06:09:25 -03:00
m_find_textbox - > on_return_pressed = [ this ] {
2019-08-24 15:09:35 -03:00
m_find_next_button - > click ( ) ;
2019-08-22 06:09:25 -03:00
} ;
m_find_textbox - > on_escape_pressed = [ this ] {
2020-01-11 15:52:47 -03:00
m_find_replace_widget - > set_visible ( false ) ;
m_editor - > set_focus ( true ) ;
2022-03-29 10:41:27 -03:00
m_editor - > reset_search_results ( ) ;
} ;
m_find_textbox - > on_change = [ this ] {
m_editor - > reset_search_results ( ) ;
2022-08-15 15:22:12 -03:00
find_text ( GUI : : TextEditor : : SearchDirection : : Forward , ShowMessageIfNoResults : : No ) ;
2020-01-11 15:52:47 -03:00
} ;
2021-02-21 21:01:26 -03:00
m_replace_button = * find_descendant_of_type_named < GUI : : Button > ( " replace_button " ) ;
m_replace_button - > set_action ( * m_replace_action ) ;
2020-01-11 15:52:47 -03:00
2021-01-01 04:57:48 -03:00
m_replace_all_button = * find_descendant_of_type_named < GUI : : Button > ( " replace_all_button " ) ;
2020-01-11 15:52:47 -03:00
m_replace_all_button - > set_action ( * m_replace_all_action ) ;
m_replace_textbox - > on_return_pressed = [ this ] {
2021-02-21 21:01:26 -03:00
m_replace_button - > click ( ) ;
2020-01-11 15:52:47 -03:00
} ;
m_replace_textbox - > on_escape_pressed = [ this ] {
m_find_replace_widget - > set_visible ( false ) ;
2019-08-22 06:09:25 -03:00
m_editor - > set_focus ( true ) ;
} ;
2021-04-09 11:34:51 -03:00
m_vim_emulation_setting_action = GUI : : Action : : create_checkable ( " &Vim Emulation " , { Mod_Ctrl | Mod_Shift | Mod_Alt , Key_V } , [ & ] ( auto & action ) {
2021-01-02 07:59:55 -03:00
if ( action . is_checked ( ) )
m_editor - > set_editing_engine ( make < GUI : : VimEditingEngine > ( ) ) ;
else
m_editor - > set_editing_engine ( make < GUI : : RegularEditingEngine > ( ) ) ;
} ) ;
m_vim_emulation_setting_action - > set_checked ( false ) ;
2023-01-20 16:06:05 -03:00
m_find_replace_action = GUI : : Action : : create ( " &Find/Replace... " , { Mod_Ctrl | Mod_Shift , Key_F } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/find.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ this ] ( auto & ) {
2020-01-11 15:52:47 -03:00
m_find_replace_widget - > set_visible ( true ) ;
2019-08-22 06:09:25 -03:00
m_find_widget - > set_visible ( true ) ;
2020-01-11 15:52:47 -03:00
m_replace_widget - > set_visible ( true ) ;
2019-08-22 06:02:03 -03:00
m_find_textbox - > set_focus ( true ) ;
2020-01-11 16:08:35 -03:00
if ( m_editor - > has_selection ( ) ) {
auto selected_text = m_editor - > document ( ) . text_in_range ( m_editor - > normalized_selection ( ) ) ;
m_find_textbox - > set_text ( selected_text ) ;
}
2019-08-25 16:44:59 -03:00
m_find_textbox - > select_all ( ) ;
2019-08-22 06:02:03 -03:00
} ) ;
2020-01-11 15:52:47 -03:00
m_editor - > add_custom_context_menu_action ( * m_find_replace_action ) ;
2019-08-25 16:38:13 -03:00
m_editor - > add_custom_context_menu_action ( * m_find_next_action ) ;
m_editor - > add_custom_context_menu_action ( * m_find_previous_action ) ;
2022-02-22 17:03:16 -03:00
m_line_column_statusbar_menu = GUI : : Menu : : construct ( ) ;
m_syntax_statusbar_menu = GUI : : Menu : : construct ( ) ;
2021-04-13 11:18:20 -03:00
m_statusbar = * find_descendant_of_type_named < GUI : : Statusbar > ( " statusbar " ) ;
2022-02-22 17:03:16 -03:00
m_statusbar - > segment ( 1 ) . set_mode ( GUI : : Statusbar : : Segment : : Mode : : Auto ) ;
m_statusbar - > segment ( 1 ) . set_clickable ( true ) ;
m_statusbar - > segment ( 1 ) . set_menu ( m_syntax_statusbar_menu ) ;
m_statusbar - > segment ( 2 ) . set_mode ( GUI : : Statusbar : : Segment : : Mode : : Fixed ) ;
2023-04-11 13:39:26 -03:00
auto width = font ( ) . width ( " Ln 0,000 Col 000 " sv ) + font ( ) . max_glyph_width ( ) ;
2022-02-22 17:03:16 -03:00
m_statusbar - > segment ( 2 ) . set_fixed_width ( width ) ;
m_statusbar - > segment ( 2 ) . set_clickable ( true ) ;
m_statusbar - > segment ( 2 ) . set_menu ( m_line_column_statusbar_menu ) ;
2019-07-11 15:52:33 -03:00
2021-04-17 13:44:45 -03:00
GUI : : Application : : the ( ) - > on_action_enter = [ this ] ( GUI : : Action & action ) {
2023-06-04 07:10:25 -03:00
m_statusbar - > set_override_text ( action . status_tip ( ) ) ;
2021-04-17 13:44:45 -03:00
} ;
GUI : : Application : : the ( ) - > on_action_leave = [ this ] ( GUI : : Action & ) {
m_statusbar - > set_override_text ( { } ) ;
} ;
2021-03-14 09:58:57 -03:00
m_editor - > on_cursor_change = [ this ] { update_statusbar ( ) ; } ;
m_editor - > on_selection_change = [ this ] { update_statusbar ( ) ; } ;
2022-02-22 17:03:16 -03:00
m_editor - > on_highlighter_change = [ this ] { update_statusbar ( ) ; } ;
2019-07-11 15:52:33 -03:00
2023-01-20 16:06:05 -03:00
m_new_action = GUI : : Action : : create ( " &New " , { Mod_Ctrl , Key_N } , Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/new.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ this ] ( GUI : : Action const & ) {
2021-05-01 13:51:43 -03:00
if ( editor ( ) . document ( ) . is_modified ( ) ) {
2022-01-04 13:34:10 -03:00
auto save_document_first_result = GUI : : MessageBox : : ask_about_unsaved_changes ( window ( ) , m_path , editor ( ) . document ( ) . undo_stack ( ) . last_unmodified_timestamp ( ) ) ;
2022-05-13 09:10:27 -03:00
if ( save_document_first_result = = GUI : : Dialog : : ExecResult : : Yes )
2020-02-17 02:06:11 -03:00
m_save_action - > activate ( ) ;
2022-05-13 09:10:27 -03:00
if ( save_document_first_result ! = GUI : : Dialog : : ExecResult : : No & & editor ( ) . document ( ) . is_modified ( ) )
2019-09-14 17:10:44 -03:00
return ;
2019-09-06 02:05:28 -03:00
}
2019-09-14 17:10:44 -03:00
2019-09-06 02:05:28 -03:00
m_editor - > set_text ( StringView ( ) ) ;
2021-06-29 15:12:53 -03:00
set_path ( { } ) ;
2019-09-06 02:05:28 -03:00
update_title ( ) ;
2019-07-11 15:52:33 -03:00
} ) ;
2020-02-02 11:07:41 -03:00
m_open_action = GUI : : CommonActions : : make_open_action ( [ this ] ( auto & ) {
2021-05-01 13:51:43 -03:00
if ( editor ( ) . document ( ) . is_modified ( ) ) {
2022-01-04 13:34:10 -03:00
auto save_document_first_result = GUI : : MessageBox : : ask_about_unsaved_changes ( window ( ) , m_path , editor ( ) . document ( ) . undo_stack ( ) . last_unmodified_timestamp ( ) ) ;
2022-05-13 09:10:27 -03:00
if ( save_document_first_result = = GUI : : Dialog : : ExecResult : : Yes )
2019-12-21 19:20:43 -03:00
m_save_action - > activate ( ) ;
2022-05-13 09:10:27 -03:00
if ( save_document_first_result ! = GUI : : Dialog : : ExecResult : : No & & editor ( ) . document ( ) . is_modified ( ) )
2020-02-17 02:06:11 -03:00
return ;
2019-12-21 19:20:43 -03:00
}
2023-01-14 19:45:51 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . open_file ( window ( ) ) ;
2022-02-14 09:03:42 -03:00
if ( response . is_error ( ) )
return ;
2023-01-14 20:02:35 -03:00
if ( auto result = read_file ( response . value ( ) . filename ( ) , response . value ( ) . stream ( ) ) ; result . is_error ( ) )
GUI : : MessageBox : : show ( window ( ) , " Unable to open file. \n " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2019-07-11 15:52:33 -03:00
} ) ;
2020-11-01 18:32:27 -03:00
m_save_as_action = GUI : : CommonActions : : make_save_as_action ( [ & ] ( auto & ) {
2022-12-06 15:32:17 -03:00
auto extension = m_extension ;
if ( extension . is_null ( ) & & m_editor - > syntax_highlighter ( ) )
extension = Syntax : : common_language_extension ( m_editor - > syntax_highlighter ( ) - > language ( ) ) ;
2023-01-14 19:45:51 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . save_file ( window ( ) , m_name , extension ) ;
2022-01-17 00:43:40 -03:00
if ( response . is_error ( ) )
2019-07-13 21:58:04 -03:00
return ;
2022-01-17 00:43:40 -03:00
auto file = response . release_value ( ) ;
2023-01-14 19:45:51 -03:00
if ( auto result = m_editor - > write_to_file ( file . stream ( ) ) ; result . is_error ( ) ) {
2022-07-11 14:32:29 -03:00
GUI : : MessageBox : : show ( window ( ) , " Unable to save file. \n " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2019-07-13 21:58:04 -03:00
return ;
}
2021-05-01 14:07:57 -03:00
2023-01-14 19:45:51 -03:00
set_path ( file . filename ( ) ) ;
2023-02-06 14:44:11 -03:00
GUI : : Application : : the ( ) - > set_most_recently_open_file ( file . filename ( ) ) ;
2023-01-14 19:45:51 -03:00
dbgln ( " Wrote document to {} " , file . filename ( ) ) ;
2019-07-24 01:32:30 -03:00
} ) ;
2020-11-01 18:32:27 -03:00
m_save_action = GUI : : CommonActions : : make_save_action ( [ & ] ( auto & ) {
2022-01-04 13:44:32 -03:00
if ( m_path . is_empty ( ) ) {
m_save_as_action - > activate ( ) ;
return ;
}
2023-02-08 23:02:46 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . request_file ( window ( ) , m_path , Core : : File : : OpenMode : : Truncate | Core : : File : : OpenMode : : Write ) ;
2022-01-17 00:43:40 -03:00
if ( response . is_error ( ) )
2019-07-24 01:32:30 -03:00
return ;
2022-01-04 13:44:32 -03:00
2023-01-14 19:45:51 -03:00
if ( auto result = m_editor - > write_to_file ( response . value ( ) . stream ( ) ) ; result . is_error ( ) ) {
2022-07-11 14:32:29 -03:00
GUI : : MessageBox : : show ( window ( ) , " Unable to save file. \n " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2022-01-04 13:44:32 -03:00
}
2019-07-11 15:52:33 -03:00
} ) ;
2023-01-20 16:06:05 -03:00
auto file_manager_icon = Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/app-file-manager.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) ;
2023-02-06 12:26:55 -03:00
m_open_folder_action = GUI : : Action : : create ( " Reveal in File Manager " , { Mod_Ctrl | Mod_Shift , Key_O } , file_manager_icon , [ & ] ( auto & ) {
2022-12-23 09:13:42 -03:00
auto lexical_path = LexicalPath ( m_path ) ;
Desktop : : Launcher : : open ( URL : : create_with_file_scheme ( lexical_path . dirname ( ) , lexical_path . basename ( ) ) ) ;
} ) ;
m_open_folder_action - > set_enabled ( ! m_path . is_empty ( ) ) ;
2023-08-07 06:12:38 -03:00
m_open_folder_action - > set_status_tip ( " Open the current file location in File Manager " _string ) ;
2022-12-23 09:13:42 -03:00
2021-02-26 09:16:40 -03:00
m_toolbar - > add_action ( * m_new_action ) ;
m_toolbar - > add_action ( * m_open_action ) ;
m_toolbar - > add_action ( * m_save_action ) ;
m_toolbar - > add_separator ( ) ;
2022-12-23 09:13:42 -03:00
m_toolbar - > add_action ( * m_open_folder_action ) ;
m_toolbar - > add_separator ( ) ;
2021-02-26 09:16:40 -03:00
m_toolbar - > add_action ( m_editor - > cut_action ( ) ) ;
m_toolbar - > add_action ( m_editor - > copy_action ( ) ) ;
m_toolbar - > add_action ( m_editor - > paste_action ( ) ) ;
m_toolbar - > add_separator ( ) ;
m_toolbar - > add_action ( m_editor - > undo_action ( ) ) ;
m_toolbar - > add_action ( m_editor - > redo_action ( ) ) ;
}
2022-04-30 05:46:33 -03:00
WebView : : OutOfProcessWebView & MainWidget : : ensure_web_view ( )
2021-05-20 17:00:31 -03:00
{
if ( ! m_page_view ) {
auto & web_view_container = * find_descendant_of_type_named < GUI : : Widget > ( " web_view_container " ) ;
2022-04-30 05:46:33 -03:00
m_page_view = web_view_container . add < WebView : : OutOfProcessWebView > ( ) ;
2021-05-20 17:00:31 -03:00
m_page_view - > on_link_hover = [ this ] ( auto & url ) {
if ( url . is_valid ( ) )
2023-06-04 05:24:38 -03:00
m_statusbar - > set_text ( String : : from_deprecated_string ( url . to_deprecated_string ( ) ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2021-05-20 17:00:31 -03:00
else
update_statusbar ( ) ;
} ;
m_page_view - > on_link_click = [ & ] ( auto & url , auto & , unsigned ) {
if ( ! Desktop : : Launcher : : open ( url ) ) {
GUI : : MessageBox : : show (
window ( ) ,
2022-12-04 15:02:33 -03:00
DeprecatedString : : formatted ( " The link to '{}' could not be opened. " , url ) ,
2022-07-11 14:32:29 -03:00
" Failed to open link " sv ,
2021-05-20 17:00:31 -03:00
GUI : : MessageBox : : Type : : Error ) ;
}
} ;
}
return * m_page_view ;
}
2023-04-16 09:44:26 -03:00
ErrorOr < void > MainWidget : : initialize_menubar ( GUI : : Window & window )
2021-02-26 09:16:40 -03:00
{
2023-08-14 05:44:42 -03:00
auto file_menu = window . add_menu ( " &File " _string ) ;
2023-08-14 05:14:27 -03:00
file_menu - > add_action ( * m_new_action ) ;
file_menu - > add_action ( * m_open_action ) ;
file_menu - > add_action ( * m_save_action ) ;
file_menu - > add_action ( * m_save_as_action ) ;
2023-08-14 02:19:40 -03:00
file_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
file_menu - > add_action ( * m_open_folder_action ) ;
2023-08-14 02:19:40 -03:00
file_menu - > add_separator ( ) ;
2023-04-16 09:44:26 -03:00
2023-08-14 05:16:18 -03:00
file_menu - > add_recent_files_list ( [ & ] ( auto & action ) {
2023-02-06 14:44:11 -03:00
if ( editor ( ) . document ( ) . is_modified ( ) ) {
auto save_document_first_result = GUI : : MessageBox : : ask_about_unsaved_changes ( & window , m_path , editor ( ) . document ( ) . undo_stack ( ) . last_unmodified_timestamp ( ) ) ;
if ( save_document_first_result = = GUI : : Dialog : : ExecResult : : Yes )
m_save_action - > activate ( ) ;
if ( save_document_first_result ! = GUI : : Dialog : : ExecResult : : No & & editor ( ) . document ( ) . is_modified ( ) )
return ;
}
2023-03-16 17:50:39 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . request_file_read_only_approved ( & window , action . text ( ) ) ;
2023-02-06 14:44:11 -03:00
if ( response . is_error ( ) )
return ;
if ( auto result = read_file ( response . value ( ) . filename ( ) , response . value ( ) . stream ( ) ) ; result . is_error ( ) )
GUI : : MessageBox : : show ( & window , " Unable to open file. \n " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2023-08-14 05:16:18 -03:00
} ) ;
2023-08-14 05:14:27 -03:00
file_menu - > add_action ( GUI : : CommonActions : : make_quit_action ( [ this ] ( auto & ) {
2019-08-27 15:37:41 -03:00
if ( ! request_close ( ) )
return ;
2020-07-04 11:52:01 -03:00
GUI : : Application : : the ( ) - > quit ( ) ;
2023-08-14 05:14:27 -03:00
} ) ) ;
2023-04-16 09:44:26 -03:00
2023-08-14 05:44:42 -03:00
auto edit_menu = window . add_menu ( " &Edit " _string ) ;
2023-08-14 05:14:27 -03:00
edit_menu - > add_action ( m_editor - > undo_action ( ) ) ;
edit_menu - > add_action ( m_editor - > redo_action ( ) ) ;
2023-08-14 02:19:40 -03:00
edit_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
edit_menu - > add_action ( m_editor - > cut_action ( ) ) ;
edit_menu - > add_action ( m_editor - > copy_action ( ) ) ;
edit_menu - > add_action ( m_editor - > paste_action ( ) ) ;
2023-08-14 02:19:40 -03:00
edit_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
edit_menu - > add_action ( m_editor - > insert_emoji_action ( ) ) ;
edit_menu - > add_action ( * m_vim_emulation_setting_action ) ;
2023-08-14 02:19:40 -03:00
edit_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
edit_menu - > add_action ( * m_find_replace_action ) ;
edit_menu - > add_action ( * m_find_next_action ) ;
edit_menu - > add_action ( * m_find_previous_action ) ;
edit_menu - > add_action ( * m_replace_action ) ;
edit_menu - > add_action ( * m_replace_all_action ) ;
2020-04-04 07:18:40 -03:00
2020-07-04 16:19:01 -03:00
m_no_preview_action = GUI : : Action : : create_checkable (
2021-04-09 11:34:51 -03:00
" &No Preview " , [ this ] ( auto & ) {
2020-07-04 16:19:01 -03:00
set_preview_mode ( PreviewMode : : None ) ;
} ) ;
2020-04-29 06:48:11 -03:00
m_markdown_preview_action = GUI : : Action : : create_checkable (
2021-04-09 11:34:51 -03:00
" &Markdown Preview " , [ this ] ( auto & ) {
2020-07-04 16:19:01 -03:00
set_preview_mode ( PreviewMode : : Markdown ) ;
2020-04-29 06:48:11 -03:00
} ,
this ) ;
2020-06-26 17:47:29 -03:00
m_html_preview_action = GUI : : Action : : create_checkable (
2021-04-09 11:34:51 -03:00
" &HTML Preview " , [ this ] ( auto & ) {
2020-07-04 16:19:01 -03:00
set_preview_mode ( PreviewMode : : HTML ) ;
2020-06-26 17:47:29 -03:00
} ,
this ) ;
2020-07-04 16:19:01 -03:00
m_preview_actions . add_action ( * m_no_preview_action ) ;
2020-06-26 17:47:29 -03:00
m_preview_actions . add_action ( * m_markdown_preview_action ) ;
m_preview_actions . add_action ( * m_html_preview_action ) ;
m_preview_actions . set_exclusive ( true ) ;
2021-04-09 11:34:51 -03:00
m_layout_toolbar_action = GUI : : Action : : create_checkable ( " &Toolbar " , [ & ] ( auto & action ) {
2021-02-26 09:16:40 -03:00
action . is_checked ( ) ? m_toolbar_container - > set_visible ( true ) : m_toolbar_container - > set_visible ( false ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " TextEditor " sv , " Layout " sv , " ShowToolbar " sv , action . is_checked ( ) ) ;
2021-02-12 14:34:04 -03:00
} ) ;
2022-07-11 14:32:29 -03:00
auto show_toolbar = Config : : read_bool ( " TextEditor " sv , " Layout " sv , " ShowToolbar " sv , true ) ;
2021-02-12 14:34:04 -03:00
m_layout_toolbar_action - > set_checked ( show_toolbar ) ;
2021-02-26 09:16:40 -03:00
m_toolbar_container - > set_visible ( show_toolbar ) ;
2021-02-12 14:34:04 -03:00
2021-04-09 11:34:51 -03:00
m_layout_statusbar_action = GUI : : Action : : create_checkable ( " &Status Bar " , [ & ] ( auto & action ) {
2021-02-12 14:34:04 -03:00
action . is_checked ( ) ? m_statusbar - > set_visible ( true ) : m_statusbar - > set_visible ( false ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " TextEditor " sv , " Layout " sv , " ShowStatusbar " sv , action . is_checked ( ) ) ;
2022-02-22 17:03:16 -03:00
update_statusbar ( ) ;
2021-02-12 14:34:04 -03:00
} ) ;
2022-07-11 14:32:29 -03:00
auto show_statusbar = Config : : read_bool ( " TextEditor " sv , " Layout " sv , " ShowStatusbar " sv , true ) ;
2021-02-12 14:34:04 -03:00
m_layout_statusbar_action - > set_checked ( show_statusbar ) ;
m_statusbar - > set_visible ( show_statusbar ) ;
2022-02-26 17:27:28 -03:00
m_layout_ruler_action = GUI : : Action : : create_checkable ( " &Ruler " , [ & ] ( auto & action ) {
2021-02-12 14:34:04 -03:00
action . is_checked ( ) ? m_editor - > set_ruler_visible ( true ) : m_editor - > set_ruler_visible ( false ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " TextEditor " sv , " Layout " sv , " ShowRuler " sv , action . is_checked ( ) ) ;
2021-02-12 14:34:04 -03:00
} ) ;
2022-07-11 14:32:29 -03:00
auto show_ruler = Config : : read_bool ( " TextEditor " sv , " Layout " sv , " ShowRuler " sv , true ) ;
2021-02-12 14:34:04 -03:00
m_layout_ruler_action - > set_checked ( show_ruler ) ;
m_editor - > set_ruler_visible ( show_ruler ) ;
2023-08-14 05:44:42 -03:00
auto view_menu = window . add_menu ( " &View " _string ) ;
2023-08-14 04:04:41 -03:00
auto layout_menu = view_menu - > add_submenu ( " &Layout " _string ) ;
2023-08-14 05:14:27 -03:00
layout_menu - > add_action ( * m_layout_toolbar_action ) ;
layout_menu - > add_action ( * m_layout_statusbar_action ) ;
layout_menu - > add_action ( * m_layout_ruler_action ) ;
2021-02-12 14:34:04 -03:00
2023-08-14 02:19:40 -03:00
view_menu - > add_separator ( ) ;
2021-02-12 14:34:04 -03:00
2023-08-14 05:14:27 -03:00
view_menu - > add_action ( GUI : : Action : : create ( " Change &Font... " , TRY ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/app-font-editor.png " sv ) ) ,
2020-12-30 14:04:55 -03:00
[ & ] ( auto & ) {
2021-07-21 16:21:03 -03:00
auto picker = GUI : : FontPicker : : construct ( & window , & m_editor - > font ( ) , false ) ;
2022-05-13 09:10:27 -03:00
if ( picker - > exec ( ) = = GUI : : Dialog : : ExecResult : : OK ) {
2020-12-30 14:04:55 -03:00
dbgln ( " setting font {} " , picker - > font ( ) - > qualified_name ( ) ) ;
m_editor - > set_font ( picker - > font ( ) ) ;
2022-10-23 17:16:43 -03:00
Config : : write_string ( " TextEditor " sv , " Text " sv , " Font " sv , picker - > font ( ) - > qualified_name ( ) ) ;
2020-12-30 14:04:55 -03:00
}
2023-08-14 05:14:27 -03:00
} ) ) ;
2020-12-30 14:04:55 -03:00
2023-08-14 02:19:40 -03:00
view_menu - > add_separator ( ) ;
2021-01-09 09:47:48 -03:00
m_wrapping_mode_actions . set_exclusive ( true ) ;
2023-08-14 04:04:41 -03:00
auto wrapping_mode_menu = view_menu - > add_submenu ( " &Wrapping Mode " _string ) ;
2021-04-09 11:34:51 -03:00
m_no_wrapping_action = GUI : : Action : : create_checkable ( " &No Wrapping " , [ & ] ( auto & ) {
2021-01-09 09:47:48 -03:00
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : NoWrap ) ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " TextEditor " sv , " View " sv , " WrappingMode " sv , " None " sv ) ;
2021-01-09 09:47:48 -03:00
} ) ;
2021-04-09 11:34:51 -03:00
m_wrap_anywhere_action = GUI : : Action : : create_checkable ( " Wrap &Anywhere " , [ & ] ( auto & ) {
2021-01-09 09:47:48 -03:00
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : WrapAnywhere ) ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " TextEditor " sv , " View " sv , " WrappingMode " sv , " Anywhere " sv ) ;
2021-01-09 09:47:48 -03:00
} ) ;
2021-04-09 11:34:51 -03:00
m_wrap_at_words_action = GUI : : Action : : create_checkable ( " Wrap at &Words " , [ & ] ( auto & ) {
2021-01-09 09:47:48 -03:00
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : WrapAtWords ) ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " TextEditor " sv , " View " sv , " WrappingMode " sv , " Words " sv ) ;
2021-01-09 09:47:48 -03:00
} ) ;
m_wrapping_mode_actions . add_action ( * m_no_wrapping_action ) ;
m_wrapping_mode_actions . add_action ( * m_wrap_anywhere_action ) ;
m_wrapping_mode_actions . add_action ( * m_wrap_at_words_action ) ;
2023-08-14 05:14:27 -03:00
wrapping_mode_menu - > add_action ( * m_no_wrapping_action ) ;
wrapping_mode_menu - > add_action ( * m_wrap_anywhere_action ) ;
wrapping_mode_menu - > add_action ( * m_wrap_at_words_action ) ;
2021-01-09 09:47:48 -03:00
2022-07-11 14:32:29 -03:00
auto word_wrap = Config : : read_string ( " TextEditor " sv , " View " sv , " WrappingMode " sv , " Words " sv ) ;
2022-02-26 17:28:55 -03:00
if ( word_wrap = = " None " ) {
m_no_wrapping_action - > set_checked ( true ) ;
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : NoWrap ) ;
} else if ( word_wrap = = " Anywhere " ) {
m_wrap_anywhere_action - > set_checked ( true ) ;
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : WrapAnywhere ) ;
} else {
m_wrap_at_words_action - > set_checked ( true ) ;
m_editor - > set_wrapping_mode ( GUI : : TextEditor : : WrappingMode : : WrapAtWords ) ;
}
2021-01-09 09:47:48 -03:00
2021-03-15 18:28:24 -03:00
m_soft_tab_width_actions . set_exclusive ( true ) ;
2023-08-14 04:04:41 -03:00
auto soft_tab_width_menu = view_menu - > add_submenu ( " &Tab Width " _string ) ;
2021-03-15 18:28:24 -03:00
m_soft_tab_1_width_action = GUI : : Action : : create_checkable ( " 1 " , [ & ] ( auto & ) {
m_editor - > set_soft_tab_width ( 1 ) ;
} ) ;
m_soft_tab_2_width_action = GUI : : Action : : create_checkable ( " 2 " , [ & ] ( auto & ) {
m_editor - > set_soft_tab_width ( 2 ) ;
} ) ;
m_soft_tab_4_width_action = GUI : : Action : : create_checkable ( " 4 " , [ & ] ( auto & ) {
m_editor - > set_soft_tab_width ( 4 ) ;
} ) ;
m_soft_tab_8_width_action = GUI : : Action : : create_checkable ( " 8 " , [ & ] ( auto & ) {
m_editor - > set_soft_tab_width ( 8 ) ;
} ) ;
m_soft_tab_16_width_action = GUI : : Action : : create_checkable ( " 16 " , [ & ] ( auto & ) {
m_editor - > set_soft_tab_width ( 16 ) ;
} ) ;
2021-03-17 13:52:54 -03:00
m_soft_tab_width_actions . add_action ( * m_soft_tab_1_width_action ) ;
m_soft_tab_width_actions . add_action ( * m_soft_tab_2_width_action ) ;
m_soft_tab_width_actions . add_action ( * m_soft_tab_4_width_action ) ;
m_soft_tab_width_actions . add_action ( * m_soft_tab_8_width_action ) ;
m_soft_tab_width_actions . add_action ( * m_soft_tab_16_width_action ) ;
2023-08-14 05:14:27 -03:00
soft_tab_width_menu - > add_action ( * m_soft_tab_1_width_action ) ;
soft_tab_width_menu - > add_action ( * m_soft_tab_2_width_action ) ;
soft_tab_width_menu - > add_action ( * m_soft_tab_4_width_action ) ;
soft_tab_width_menu - > add_action ( * m_soft_tab_8_width_action ) ;
soft_tab_width_menu - > add_action ( * m_soft_tab_16_width_action ) ;
2021-03-15 18:28:24 -03:00
m_soft_tab_4_width_action - > set_checked ( true ) ;
2023-08-14 02:19:40 -03:00
view_menu - > add_separator ( ) ;
2021-03-17 13:52:54 -03:00
2021-09-11 12:30:03 -03:00
m_visualize_trailing_whitespace_action = GUI : : Action : : create_checkable ( " T&railing Whitespace " , [ & ] ( auto & ) {
2021-03-17 13:52:54 -03:00
m_editor - > set_visualize_trailing_whitespace ( m_visualize_trailing_whitespace_action - > is_checked ( ) ) ;
} ) ;
2021-09-11 12:30:03 -03:00
m_visualize_leading_whitespace_action = GUI : : Action : : create_checkable ( " L&eading Whitespace " , [ & ] ( auto & ) {
2021-03-17 13:52:54 -03:00
m_editor - > set_visualize_leading_whitespace ( m_visualize_leading_whitespace_action - > is_checked ( ) ) ;
} ) ;
m_visualize_trailing_whitespace_action - > set_checked ( true ) ;
2023-08-07 06:12:38 -03:00
m_visualize_trailing_whitespace_action - > set_status_tip ( " Visualize trailing whitespace " _string ) ;
m_visualize_leading_whitespace_action - > set_status_tip ( " Visualize leading whitespace " _string ) ;
2021-03-17 13:52:54 -03:00
2023-08-14 05:14:27 -03:00
view_menu - > add_action ( * m_visualize_trailing_whitespace_action ) ;
view_menu - > add_action ( * m_visualize_leading_whitespace_action ) ;
2021-03-17 13:52:54 -03:00
2022-02-02 21:28:58 -03:00
m_cursor_line_highlighting_action = GUI : : Action : : create_checkable ( " L&ine Highlighting " , [ & ] ( auto & ) {
2021-09-11 12:08:01 -03:00
m_editor - > set_cursor_line_highlighting ( m_cursor_line_highlighting_action - > is_checked ( ) ) ;
} ) ;
m_cursor_line_highlighting_action - > set_checked ( true ) ;
2023-08-07 06:12:38 -03:00
m_cursor_line_highlighting_action - > set_status_tip ( " Highlight the current line " _string ) ;
2021-09-11 12:08:01 -03:00
2023-08-14 05:14:27 -03:00
view_menu - > add_action ( * m_cursor_line_highlighting_action ) ;
2021-09-11 12:08:01 -03:00
2022-12-08 06:07:50 -03:00
m_relative_line_number_action = GUI : : Action : : create_checkable ( " R&elative Line Number " , [ & ] ( auto & action ) {
m_editor - > set_relative_line_number ( action . is_checked ( ) ) ;
Config : : write_bool ( " TextEditor " sv , " View " sv , " RelativeLineNumber " sv , action . is_checked ( ) ) ;
} ) ;
auto show_relative_line_number = Config : : read_bool ( " TextEditor " sv , " View " sv , " RelativeLineNumber " sv , false ) ;
m_relative_line_number_action - > set_checked ( show_relative_line_number ) ;
m_editor - > set_relative_line_number ( show_relative_line_number ) ;
2023-08-07 06:12:38 -03:00
m_relative_line_number_action - > set_status_tip ( " Set relative line number " _string ) ;
2022-12-08 06:07:50 -03:00
2023-08-14 05:14:27 -03:00
view_menu - > add_action ( * m_relative_line_number_action ) ;
2022-12-08 06:07:50 -03:00
2023-08-14 02:19:40 -03:00
view_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
view_menu - > add_action ( * m_no_preview_action ) ;
view_menu - > add_action ( * m_markdown_preview_action ) ;
view_menu - > add_action ( * m_html_preview_action ) ;
2021-02-12 14:35:20 -03:00
m_no_preview_action - > set_checked ( true ) ;
2023-08-14 02:19:40 -03:00
view_menu - > add_separator ( ) ;
2020-04-29 06:48:11 -03:00
2020-03-10 22:02:37 -03:00
syntax_actions . set_exclusive ( true ) ;
2023-08-14 04:04:41 -03:00
auto syntax_menu = view_menu - > add_submenu ( " &Syntax " _string ) ;
2021-04-09 11:34:51 -03:00
m_plain_text_highlight = GUI : : Action : : create_checkable ( " &Plain Text " , [ & ] ( auto & ) {
2023-08-07 06:12:38 -03:00
m_statusbar - > set_text ( 1 , " Plain Text " _string ) ;
2021-01-10 20:29:28 -03:00
m_editor - > set_syntax_highlighter ( { } ) ;
2020-03-10 22:02:37 -03:00
m_editor - > update ( ) ;
} ) ;
m_plain_text_highlight - > set_checked ( true ) ;
2023-08-07 06:12:38 -03:00
m_statusbar - > set_text ( 1 , " Plain Text " _string ) ;
2020-03-10 22:02:37 -03:00
syntax_actions . add_action ( * m_plain_text_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_plain_text_highlight ) ;
2020-03-10 22:02:37 -03:00
2021-04-09 11:34:51 -03:00
m_cpp_highlight = GUI : : Action : : create_checkable ( " &C++ " , [ & ] ( auto & ) {
2021-02-07 10:40:36 -03:00
m_editor - > set_syntax_highlighter ( make < Cpp : : SyntaxHighlighter > ( ) ) ;
2020-03-10 22:02:37 -03:00
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_cpp_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_cpp_highlight ) ;
2020-03-10 22:02:37 -03:00
2023-02-28 11:32:27 -03:00
m_cmake_highlight = GUI : : Action : : create_checkable ( " C&Make " , [ & ] ( auto & ) {
m_editor - > set_syntax_highlighter ( make < CMake : : SyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_cmake_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_cmake_highlight ) ;
2023-02-28 11:32:27 -03:00
2023-03-07 17:51:48 -03:00
m_cmakecache_highlight = GUI : : Action : : create_checkable ( " CM&akeCache " , [ & ] ( auto & ) {
m_editor - > set_syntax_highlighter ( make < CMake : : Cache : : SyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_cmakecache_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_cmakecache_highlight ) ;
2023-03-07 17:51:48 -03:00
2021-04-09 11:34:51 -03:00
m_js_highlight = GUI : : Action : : create_checkable ( " &JavaScript " , [ & ] ( auto & ) {
2021-02-07 12:56:02 -03:00
m_editor - > set_syntax_highlighter ( make < JS : : SyntaxHighlighter > ( ) ) ;
2020-03-12 19:53:22 -03:00
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_js_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_js_highlight ) ;
2020-03-12 19:53:22 -03:00
2022-02-26 17:27:28 -03:00
m_css_highlight = GUI : : Action : : create_checkable ( " C&SS " , [ & ] ( auto & ) {
2021-10-21 17:45:24 -03:00
m_editor - > set_syntax_highlighter ( make < Web : : CSS : : SyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_css_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_css_highlight ) ;
2021-10-21 17:45:24 -03:00
2021-05-20 15:47:30 -03:00
m_html_highlight = GUI : : Action : : create_checkable ( " &HTML File " , [ & ] ( auto & ) {
m_editor - > set_syntax_highlighter ( make < Web : : HTML : : SyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_html_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_html_highlight ) ;
2021-05-20 15:47:30 -03:00
2022-02-26 17:27:28 -03:00
m_git_highlight = GUI : : Action : : create_checkable ( " Gi&t Commit " , [ & ] ( auto & ) {
2022-01-18 00:39:48 -03:00
m_editor - > set_syntax_highlighter ( make < GUI : : GitCommitSyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_git_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_git_highlight ) ;
2022-01-18 00:39:48 -03:00
2021-04-09 11:34:51 -03:00
m_gml_highlight = GUI : : Action : : create_checkable ( " &GML " , [ & ] ( auto & ) {
2022-02-02 14:11:29 -03:00
m_editor - > set_syntax_highlighter ( make < GUI : : GML : : SyntaxHighlighter > ( ) ) ;
2020-12-21 09:59:21 -03:00
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_gml_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_gml_highlight ) ;
2020-12-21 09:59:21 -03:00
2021-04-09 11:34:51 -03:00
m_ini_highlight = GUI : : Action : : create_checkable ( " &INI File " , [ & ] ( auto & ) {
2020-04-30 19:57:06 -03:00
m_editor - > set_syntax_highlighter ( make < GUI : : IniSyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_ini_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_ini_highlight ) ;
2020-04-30 19:57:06 -03:00
2023-04-27 07:52:01 -03:00
m_markdown_highlight = GUI : : Action : : create_checkable ( " Ma&rkdown " , [ & ] ( auto & ) {
m_editor - > set_syntax_highlighter ( make < Markdown : : SyntaxHighlighter > ( ) ) ;
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_markdown_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_markdown_highlight ) ;
2023-04-27 07:52:01 -03:00
2022-02-26 17:27:28 -03:00
m_shell_highlight = GUI : : Action : : create_checkable ( " Sh&ell File " , [ & ] ( auto & ) {
2021-02-07 13:07:33 -03:00
m_editor - > set_syntax_highlighter ( make < Shell : : SyntaxHighlighter > ( ) ) ;
2020-09-28 07:58:44 -03:00
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_shell_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_shell_highlight ) ;
2020-09-28 07:58:44 -03:00
2021-05-08 22:30:44 -03:00
m_sql_highlight = GUI : : Action : : create_checkable ( " S&QL File " , [ & ] ( auto & ) {
2021-06-21 11:57:44 -03:00
m_editor - > set_syntax_highlighter ( make < SQL : : AST : : SyntaxHighlighter > ( ) ) ;
2021-05-08 22:30:44 -03:00
m_editor - > update ( ) ;
} ) ;
syntax_actions . add_action ( * m_sql_highlight ) ;
2023-08-14 05:14:27 -03:00
syntax_menu - > add_action ( * m_sql_highlight ) ;
2021-05-08 22:30:44 -03:00
2023-08-14 05:44:42 -03:00
auto help_menu = window . add_menu ( " &Help " _string ) ;
2023-08-14 05:14:27 -03:00
help_menu - > add_action ( GUI : : CommonActions : : make_command_palette_action ( & window ) ) ;
help_menu - > add_action ( GUI : : CommonActions : : make_help_action ( [ ] ( auto & ) {
2023-04-08 06:48:22 -03:00
Desktop : : Launcher : : open ( URL : : create_with_file_scheme ( " /usr/share/man/man1/Applications/TextEditor.md " ) , " /bin/Help " ) ;
2023-08-14 05:14:27 -03:00
} ) ) ;
2023-09-13 16:34:46 -03:00
help_menu - > add_action ( GUI : : CommonActions : : make_about_action ( " Text Editor " _string , GUI : : Icon : : default_icon ( " app-text-editor " sv ) , & window ) ) ;
2023-04-16 09:44:26 -03:00
2023-08-14 04:04:41 -03:00
auto wrapping_statusbar_menu = m_line_column_statusbar_menu - > add_submenu ( " &Wrapping Mode " _string ) ;
2023-08-14 05:14:27 -03:00
wrapping_statusbar_menu - > add_action ( * m_no_wrapping_action ) ;
wrapping_statusbar_menu - > add_action ( * m_wrap_anywhere_action ) ;
wrapping_statusbar_menu - > add_action ( * m_wrap_at_words_action ) ;
2023-04-16 09:44:26 -03:00
2023-08-14 04:04:41 -03:00
auto tab_width_statusbar_menu = m_line_column_statusbar_menu - > add_submenu ( " &Tab Width " _string ) ;
2023-08-14 05:14:27 -03:00
tab_width_statusbar_menu - > add_action ( * m_soft_tab_1_width_action ) ;
tab_width_statusbar_menu - > add_action ( * m_soft_tab_2_width_action ) ;
tab_width_statusbar_menu - > add_action ( * m_soft_tab_4_width_action ) ;
tab_width_statusbar_menu - > add_action ( * m_soft_tab_8_width_action ) ;
tab_width_statusbar_menu - > add_action ( * m_soft_tab_16_width_action ) ;
2023-04-16 09:44:26 -03:00
2023-08-14 02:19:40 -03:00
m_line_column_statusbar_menu - > add_separator ( ) ;
2023-08-14 05:14:27 -03:00
m_line_column_statusbar_menu - > add_action ( * m_cursor_line_highlighting_action ) ;
m_syntax_statusbar_menu - > add_action ( * m_plain_text_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_cpp_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_cmake_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_cmakecache_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_css_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_git_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_gml_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_html_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_ini_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_js_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_markdown_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_shell_highlight ) ;
m_syntax_statusbar_menu - > add_action ( * m_sql_highlight ) ;
2023-04-16 09:44:26 -03:00
return { } ;
2019-07-11 15:52:33 -03:00
}
2021-11-10 20:55:02 -03:00
void MainWidget : : set_path ( StringView path )
2019-07-24 01:32:30 -03:00
{
2021-06-29 15:12:53 -03:00
if ( path . is_empty ( ) ) {
m_path = { } ;
m_name = { } ;
m_extension = { } ;
} else {
auto lexical_path = LexicalPath ( path ) ;
m_path = lexical_path . string ( ) ;
m_name = lexical_path . title ( ) ;
m_extension = lexical_path . extension ( ) ;
}
2020-02-07 16:12:25 -03:00
2021-07-29 17:31:59 -03:00
if ( m_extension = = " c " | | m_extension = = " cc " | | m_extension = = " cxx " | | m_extension = = " cpp " | | m_extension = = " c++ "
| | m_extension = = " h " | | m_extension = = " hh " | | m_extension = = " hxx " | | m_extension = = " hpp " | | m_extension = = " h++ " ) {
2020-03-10 22:02:37 -03:00
m_cpp_highlight - > activate ( ) ;
2023-02-28 11:32:27 -03:00
} else if ( m_extension = = " cmake " | | ( m_extension = = " txt " & & m_name = = " CMakeLists " ) ) {
m_cmake_highlight - > activate ( ) ;
2023-03-07 17:51:48 -03:00
} else if ( m_extension = = " txt " & & m_name = = " CMakeCache " ) {
m_cmakecache_highlight - > activate ( ) ;
2021-07-29 17:31:59 -03:00
} else if ( m_extension = = " js " | | m_extension = = " mjs " | | m_extension = = " json " ) {
2020-03-12 19:53:22 -03:00
m_js_highlight - > activate ( ) ;
2022-01-18 00:39:48 -03:00
} else if ( m_name = = " COMMIT_EDITMSG " ) {
m_git_highlight - > activate ( ) ;
2020-12-21 09:59:21 -03:00
} else if ( m_extension = = " gml " ) {
m_gml_highlight - > activate ( ) ;
2021-12-28 07:21:09 -03:00
} else if ( m_extension = = " ini " | | m_extension = = " af " ) {
2020-04-30 19:57:06 -03:00
m_ini_highlight - > activate ( ) ;
2023-04-27 07:52:01 -03:00
} else if ( m_extension = = " md " ) {
m_markdown_highlight - > activate ( ) ;
2021-07-29 16:04:29 -03:00
} else if ( m_extension = = " sh " | | m_extension = = " bash " ) {
m_shell_highlight - > activate ( ) ;
2021-05-08 22:30:44 -03:00
} else if ( m_extension = = " sql " ) {
m_sql_highlight - > activate ( ) ;
2021-07-29 16:04:29 -03:00
} else if ( m_extension = = " html " | | m_extension = = " htm " ) {
2021-05-20 15:47:30 -03:00
m_html_highlight - > activate ( ) ;
2021-10-21 17:45:24 -03:00
} else if ( m_extension = = " css " ) {
m_css_highlight - > activate ( ) ;
2020-04-28 16:42:45 -03:00
} else {
2020-03-10 22:02:37 -03:00
m_plain_text_highlight - > activate ( ) ;
2020-04-28 16:42:45 -03:00
}
2020-07-06 11:18:49 -03:00
if ( m_auto_detect_preview_mode ) {
if ( m_extension = = " md " )
set_preview_mode ( PreviewMode : : Markdown ) ;
2021-07-29 16:04:29 -03:00
else if ( m_extension = = " html " | | m_extension = = " htm " )
2020-07-06 11:18:49 -03:00
set_preview_mode ( PreviewMode : : HTML ) ;
else
set_preview_mode ( PreviewMode : : None ) ;
}
2020-02-07 16:12:25 -03:00
2022-12-23 09:13:42 -03:00
m_open_folder_action - > set_enabled ( ! path . is_empty ( ) ) ;
2019-08-27 15:18:19 -03:00
update_title ( ) ;
}
2021-05-01 13:26:44 -03:00
void MainWidget : : update_title ( )
2019-08-27 15:18:19 -03:00
{
2019-07-24 01:32:30 -03:00
StringBuilder builder ;
2020-12-29 23:44:38 -03:00
if ( m_path . is_empty ( ) )
2022-07-11 14:32:29 -03:00
builder . append ( " Untitled " sv ) ;
2020-12-29 23:44:38 -03:00
else
builder . append ( m_path ) ;
2022-07-11 14:32:29 -03:00
builder . append ( " [*] - Text Editor " sv ) ;
2022-12-05 22:12:49 -03:00
window ( ) - > set_title ( builder . to_deprecated_string ( ) ) ;
2019-07-24 01:32:30 -03:00
}
2023-02-08 23:02:46 -03:00
ErrorOr < void > MainWidget : : read_file ( String const & filename , Core : : File & file )
2019-07-11 15:52:33 -03:00
{
2023-01-14 20:02:35 -03:00
m_editor - > set_text ( TRY ( file . read_until_eof ( ) ) ) ;
2023-01-14 19:45:51 -03:00
set_path ( filename ) ;
2023-02-06 14:44:11 -03:00
GUI : : Application : : the ( ) - > set_most_recently_open_file ( filename ) ;
2020-01-23 17:29:59 -03:00
m_editor - > set_focus ( true ) ;
2023-01-14 20:02:35 -03:00
return { } ;
2019-07-16 16:32:10 -03:00
}
2019-08-27 15:37:41 -03:00
2022-12-04 15:02:33 -03:00
void MainWidget : : open_nonexistent_file ( DeprecatedString const & path )
2021-07-21 14:35:52 -03:00
{
m_editor - > set_text ( { } ) ;
set_path ( path ) ;
m_editor - > set_focus ( true ) ;
}
2021-05-01 13:26:44 -03:00
bool MainWidget : : request_close ( )
2019-08-27 15:37:41 -03:00
{
2021-05-01 13:51:43 -03:00
if ( ! editor ( ) . document ( ) . is_modified ( ) )
2019-08-27 15:37:41 -03:00
return true ;
2022-01-04 13:34:10 -03:00
auto result = GUI : : MessageBox : : ask_about_unsaved_changes ( window ( ) , m_path , editor ( ) . document ( ) . undo_stack ( ) . last_unmodified_timestamp ( ) ) ;
2020-02-17 02:06:11 -03:00
2022-05-13 09:10:27 -03:00
if ( result = = GUI : : MessageBox : : ExecResult : : Yes ) {
2020-02-17 02:06:11 -03:00
m_save_action - > activate ( ) ;
2021-06-01 04:28:48 -03:00
if ( editor ( ) . document ( ) . is_modified ( ) )
return false ;
2020-03-10 10:23:28 -03:00
return true ;
}
2020-02-17 02:06:11 -03:00
2022-05-13 09:10:27 -03:00
if ( result = = GUI : : MessageBox : : ExecResult : : No )
2020-02-17 02:06:11 -03:00
return true ;
return false ;
2019-08-27 15:37:41 -03:00
}
2019-12-19 16:20:20 -03:00
2022-11-04 18:32:17 -03:00
void MainWidget : : drag_enter_event ( GUI : : DragEvent & event )
{
auto const & mime_types = event . mime_types ( ) ;
2023-09-21 14:02:52 -03:00
if ( mime_types . contains_slow ( " text/uri-list " sv ) )
2022-11-04 18:32:17 -03:00
event . accept ( ) ;
}
2021-05-01 13:26:44 -03:00
void MainWidget : : drop_event ( GUI : : DropEvent & event )
2019-12-19 16:20:20 -03:00
{
event . accept ( ) ;
window ( ) - > move_to_front ( ) ;
2020-02-14 09:18:34 -03:00
if ( event . mime_data ( ) . has_urls ( ) ) {
auto urls = event . mime_data ( ) . urls ( ) ;
2020-02-16 05:17:49 -03:00
if ( urls . is_empty ( ) )
2019-12-19 16:20:20 -03:00
return ;
2020-02-14 09:18:34 -03:00
if ( urls . size ( ) > 1 ) {
2022-07-11 14:32:29 -03:00
GUI : : MessageBox : : show ( window ( ) , " TextEditor can only open one file at a time! " sv , " One at a time please! " sv , GUI : : MessageBox : : Type : : Error ) ;
2019-12-19 16:20:20 -03:00
return ;
}
2022-11-05 12:13:51 -03:00
if ( ! request_close ( ) )
return ;
2021-06-30 10:13:06 -03:00
2023-04-14 16:12:03 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . request_file_read_only_approved ( window ( ) , urls . first ( ) . serialize_path ( ) ) ;
2022-01-17 00:43:40 -03:00
if ( response . is_error ( ) )
2021-06-30 10:13:06 -03:00
return ;
2023-01-14 20:02:35 -03:00
if ( auto result = read_file ( response . value ( ) . filename ( ) , response . value ( ) . stream ( ) ) ; result . is_error ( ) )
GUI : : MessageBox : : show ( window ( ) , " Unable to open file. \n " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2019-12-19 16:20:20 -03:00
}
}
2020-04-28 16:42:45 -03:00
2021-05-20 17:00:31 -03:00
void MainWidget : : set_web_view_visible ( bool visible )
{
if ( ! visible & & ! m_page_view )
return ;
ensure_web_view ( ) ;
auto & web_view_container = * find_descendant_of_type_named < GUI : : Widget > ( " web_view_container " ) ;
web_view_container . set_visible ( visible ) ;
}
2021-05-01 13:26:44 -03:00
void MainWidget : : set_preview_mode ( PreviewMode mode )
2020-06-26 17:47:29 -03:00
{
2020-07-04 16:19:01 -03:00
if ( m_preview_mode = = mode )
2020-06-26 17:47:29 -03:00
return ;
2020-07-04 16:19:01 -03:00
m_preview_mode = mode ;
if ( m_preview_mode = = PreviewMode : : HTML ) {
m_html_preview_action - > set_checked ( true ) ;
2021-05-20 17:00:31 -03:00
set_web_view_visible ( true ) ;
2020-06-26 17:47:29 -03:00
update_html_preview ( ) ;
2020-07-04 16:19:01 -03:00
} else if ( m_preview_mode = = PreviewMode : : Markdown ) {
m_markdown_preview_action - > set_checked ( true ) ;
2021-05-20 17:00:31 -03:00
set_web_view_visible ( true ) ;
2020-07-04 16:19:01 -03:00
update_markdown_preview ( ) ;
} else {
m_no_preview_action - > set_checked ( true ) ;
2021-05-20 17:00:31 -03:00
set_web_view_visible ( false ) ;
2020-07-04 16:19:01 -03:00
}
2020-06-26 17:47:29 -03:00
}
2021-05-01 13:26:44 -03:00
void MainWidget : : update_preview ( )
2020-04-28 16:42:45 -03:00
{
2020-07-04 16:19:01 -03:00
switch ( m_preview_mode ) {
case PreviewMode : : Markdown :
2020-04-28 16:42:45 -03:00
update_markdown_preview ( ) ;
2020-07-04 16:19:01 -03:00
break ;
case PreviewMode : : HTML :
update_html_preview ( ) ;
break ;
default :
break ;
}
2020-04-28 16:42:45 -03:00
}
2021-05-01 13:26:44 -03:00
void MainWidget : : update_markdown_preview ( )
2020-04-28 16:42:45 -03:00
{
2020-05-11 14:55:31 -03:00
auto document = Markdown : : Document : : parse ( m_editor - > text ( ) ) ;
if ( document ) {
auto html = document - > render_to_html ( ) ;
2020-07-20 09:22:07 -03:00
auto current_scroll_pos = m_page_view - > visible_content_rect ( ) ;
2023-09-17 12:12:17 -03:00
m_page_view - > load_html ( html ) ;
2020-07-20 09:22:07 -03:00
m_page_view - > scroll_into_view ( current_scroll_pos , true , true ) ;
2020-04-28 16:42:45 -03:00
}
}
2020-06-26 17:47:29 -03:00
2021-05-01 13:26:44 -03:00
void MainWidget : : update_html_preview ( )
2020-06-26 17:47:29 -03:00
{
2020-07-20 09:22:07 -03:00
auto current_scroll_pos = m_page_view - > visible_content_rect ( ) ;
2023-09-17 12:12:17 -03:00
m_page_view - > load_html ( m_editor - > text ( ) ) ;
2020-07-20 09:22:07 -03:00
m_page_view - > scroll_into_view ( current_scroll_pos , true , true ) ;
2020-06-26 17:47:29 -03:00
}
2020-08-29 08:44:25 -03:00
2021-05-01 13:26:44 -03:00
void MainWidget : : update_statusbar ( )
2020-08-29 08:44:25 -03:00
{
2022-02-22 17:03:16 -03:00
if ( ! m_statusbar - > is_visible ( ) )
return ;
2020-08-29 08:44:25 -03:00
StringBuilder builder ;
2021-03-14 09:58:57 -03:00
if ( m_editor - > has_selection ( ) ) {
2022-12-04 15:02:33 -03:00
DeprecatedString selected_text = m_editor - > selected_text ( ) ;
2021-05-25 21:58:55 -03:00
auto word_count = m_editor - > number_of_selected_words ( ) ;
2023-04-11 13:39:26 -03:00
builder . appendff ( " {:'d} {} ({:'d} {}) selected " , selected_text . length ( ) , selected_text . length ( ) = = 1 ? " character " : " characters " , word_count , word_count ! = 1 ? " words " : " word " ) ;
2021-09-18 17:30:23 -03:00
} else {
2022-12-04 15:02:33 -03:00
DeprecatedString text = m_editor - > text ( ) ;
2021-09-18 17:30:23 -03:00
auto word_count = m_editor - > number_of_words ( ) ;
2023-04-11 13:39:26 -03:00
builder . appendff ( " {:'d} {} ({:'d} {}) " , text . length ( ) , text . length ( ) = = 1 ? " character " : " characters " , word_count , word_count ! = 1 ? " words " : " word " ) ;
2021-03-14 09:58:57 -03:00
}
2023-06-04 05:24:38 -03:00
m_statusbar - > set_text ( 0 , builder . to_string ( ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2022-02-22 17:03:16 -03:00
if ( m_editor & & m_editor - > syntax_highlighter ( ) ) {
auto language = m_editor - > syntax_highlighter ( ) - > language ( ) ;
2023-06-04 05:24:38 -03:00
m_statusbar - > set_text ( 1 , String : : from_utf8 ( Syntax : : language_to_string ( language ) ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2022-02-22 17:03:16 -03:00
}
2023-06-04 05:24:38 -03:00
m_statusbar - > set_text ( 2 , String : : formatted ( " Ln {:'d} Col {:'d} " , m_editor - > cursor ( ) . line ( ) + 1 , m_editor - > cursor ( ) . column ( ) ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2020-08-29 08:44:25 -03:00
}
2021-05-01 13:26:44 -03:00
2022-08-15 15:22:12 -03:00
void MainWidget : : find_text ( GUI : : TextEditor : : SearchDirection direction , ShowMessageIfNoResults show_message )
2022-03-29 10:41:27 -03:00
{
auto needle = m_find_textbox - > text ( ) ;
if ( needle . is_empty ( ) )
return ;
if ( m_use_regex )
m_editor - > document ( ) . update_regex_matches ( needle ) ;
auto result = m_editor - > find_text ( needle , direction ,
m_should_wrap ? GUI : : TextDocument : : SearchShouldWrap : : Yes : GUI : : TextDocument : : SearchShouldWrap : : No ,
m_use_regex , m_match_case ) ;
2022-08-15 15:22:12 -03:00
if ( ! result . is_valid ( ) & & show_message = = ShowMessageIfNoResults : : Yes ) {
2022-03-29 10:41:27 -03:00
GUI : : MessageBox : : show ( window ( ) ,
2022-12-04 15:02:33 -03:00
DeprecatedString : : formatted ( " Not found: \" {} \" " , needle ) ,
2022-07-11 14:32:29 -03:00
" Not found " sv ,
2022-03-29 10:41:27 -03:00
GUI : : MessageBox : : Type : : Information ) ;
}
}
2021-05-01 13:26:44 -03:00
}