mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:52:44 +00:00 
			
		
		
		
	LibGUI: Give GTextDocument access to the GTextEditor during commands
It's useful for the GTextDocument to have access to the initiating GTextEditor widget during the initial execution of a command. Since commands are executed via calls to GUndoCommand::redo(), we do this by wrapping the invocation of redo() in a new helper called GTextDocumentUndoCommand::execute_from(GTextDocument::Client). This is then used to fetch the current auto-indentation feature state and the soft tab width, both used by text insertion.
This commit is contained in:
		
							parent
							
								
									03d73cbaae
								
							
						
					
					
						commit
						14b83ee12f
					
				
					 3 changed files with 57 additions and 43 deletions
				
			
		|  | @ -27,6 +27,7 @@ | |||
| #include <AK/StringBuilder.h> | ||||
| #include <LibCore/CTimer.h> | ||||
| #include <LibGUI/GTextDocument.h> | ||||
| #include <LibGUI/GTextEditor.h> | ||||
| #include <ctype.h> | ||||
| 
 | ||||
| GTextDocument::GTextDocument(Client* client) | ||||
|  | @ -427,7 +428,7 @@ InsertTextCommand::InsertTextCommand(GTextDocument& document, const String& text | |||
| 
 | ||||
| void InsertTextCommand::redo() | ||||
| { | ||||
|     auto new_cursor = m_document.insert_at(m_range.start(), m_text); | ||||
|     auto new_cursor = m_document.insert_at(m_range.start(), m_text, m_client); | ||||
|     // NOTE: We don't know where the range ends until after doing redo().
 | ||||
|     //       This is okay since we always do redo() after adding this to the undo stack.
 | ||||
|     m_range.set_end(new_cursor); | ||||
|  | @ -464,26 +465,25 @@ void GTextDocument::update_undo_timer() | |||
|     m_undo_stack.finalize_current_combo(); | ||||
| } | ||||
| 
 | ||||
| GTextPosition GTextDocument::insert_at(const GTextPosition& position, const StringView& text) | ||||
| GTextPosition GTextDocument::insert_at(const GTextPosition& position, const StringView& text, const Client* client) | ||||
| { | ||||
|     GTextPosition cursor = position; | ||||
|     for (size_t i = 0; i < text.length(); ++i) | ||||
|         cursor = insert_at(cursor, text[i]); | ||||
|         cursor = insert_at(cursor, text[i], client); | ||||
|     return cursor; | ||||
| } | ||||
| 
 | ||||
| GTextPosition GTextDocument::insert_at(const GTextPosition& position, char ch) | ||||
| GTextPosition GTextDocument::insert_at(const GTextPosition& position, char ch, const Client* client) | ||||
| { | ||||
|     // FIXME: We need these from GTextEditor!
 | ||||
|     bool m_automatic_indentation_enabled = true; | ||||
|     size_t m_soft_tab_width = 4; | ||||
|     bool automatic_indentation_enabled = client ? client->is_automatic_indentation_enabled() : false; | ||||
|     size_t m_soft_tab_width = client ? client->soft_tab_width() : 4; | ||||
| 
 | ||||
|     bool at_head = position.column() == 0; | ||||
|     bool at_tail = position.column() == line(position.line()).length(); | ||||
|     if (ch == '\n') { | ||||
|         if (at_tail || at_head) { | ||||
|             String new_line_contents; | ||||
|             if (m_automatic_indentation_enabled && at_tail) { | ||||
|             if (automatic_indentation_enabled && at_tail) { | ||||
|                 size_t leading_spaces = 0; | ||||
|                 auto& old_line = lines()[position.line()]; | ||||
|                 for (size_t i = 0; i < old_line.length(); ++i) { | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ | |||
| class GTextEditor; | ||||
| class GTextDocument; | ||||
| class GTextDocumentLine; | ||||
| class GTextDocumentUndoCommand; | ||||
| 
 | ||||
| struct GTextDocumentSpan { | ||||
|     GTextRange range; | ||||
|  | @ -50,37 +51,6 @@ struct GTextDocumentSpan { | |||
|     void* data { nullptr }; | ||||
| }; | ||||
| 
 | ||||
| class GTextDocumentUndoCommand : public GCommand { | ||||
| public: | ||||
|     GTextDocumentUndoCommand(GTextDocument&); | ||||
|     virtual ~GTextDocumentUndoCommand(); | ||||
| 
 | ||||
| protected: | ||||
|     GTextDocument& m_document; | ||||
| }; | ||||
| 
 | ||||
| class InsertTextCommand : public GTextDocumentUndoCommand { | ||||
| public: | ||||
|     InsertTextCommand(GTextDocument&, const String&, const GTextPosition&); | ||||
|     virtual void undo() override; | ||||
|     virtual void redo() override; | ||||
| 
 | ||||
| private: | ||||
|     String m_text; | ||||
|     GTextRange m_range; | ||||
| }; | ||||
| 
 | ||||
| class RemoveTextCommand : public GTextDocumentUndoCommand { | ||||
| public: | ||||
|     RemoveTextCommand(GTextDocument&, const String&, const GTextRange&); | ||||
|     virtual void undo() override; | ||||
|     virtual void redo() override; | ||||
| 
 | ||||
| private: | ||||
|     String m_text; | ||||
|     GTextRange m_range; | ||||
| }; | ||||
| 
 | ||||
| class GTextDocument : public RefCounted<GTextDocument> { | ||||
| public: | ||||
|     enum class SearchShouldWrap { | ||||
|  | @ -98,6 +68,9 @@ public: | |||
|         virtual void document_did_change() = 0; | ||||
|         virtual void document_did_set_text() = 0; | ||||
|         virtual void document_did_set_cursor(const GTextPosition&) = 0; | ||||
| 
 | ||||
|         virtual bool is_automatic_indentation_enabled() const = 0; | ||||
|         virtual int soft_tab_width() const = 0; | ||||
|     }; | ||||
| 
 | ||||
|     static NonnullRefPtr<GTextDocument> create(Client* client = nullptr) | ||||
|  | @ -157,8 +130,8 @@ public: | |||
|     void notify_did_change(); | ||||
|     void set_all_cursors(const GTextPosition&); | ||||
| 
 | ||||
|     GTextPosition insert_at(const GTextPosition&, char); | ||||
|     GTextPosition insert_at(const GTextPosition&, const StringView&); | ||||
|     GTextPosition insert_at(const GTextPosition&, char, const Client* = nullptr); | ||||
|     GTextPosition insert_at(const GTextPosition&, const StringView&, const Client* = nullptr); | ||||
|     void remove(const GTextRange&); | ||||
| 
 | ||||
| private: | ||||
|  | @ -201,3 +174,42 @@ private: | |||
|     // NOTE: This vector is null terminated.
 | ||||
|     Vector<char> m_text; | ||||
| }; | ||||
| 
 | ||||
| class GTextDocumentUndoCommand : public GCommand { | ||||
| public: | ||||
|     GTextDocumentUndoCommand(GTextDocument&); | ||||
|     virtual ~GTextDocumentUndoCommand(); | ||||
| 
 | ||||
|     void execute_from(const GTextDocument::Client& client) | ||||
|     { | ||||
|         m_client = &client; | ||||
|         redo(); | ||||
|         m_client = nullptr; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     GTextDocument& m_document; | ||||
|     const GTextDocument::Client* m_client { nullptr }; | ||||
| }; | ||||
| 
 | ||||
| class InsertTextCommand : public GTextDocumentUndoCommand { | ||||
| public: | ||||
|     InsertTextCommand(GTextDocument&, const String&, const GTextPosition&); | ||||
|     virtual void undo() override; | ||||
|     virtual void redo() override; | ||||
| 
 | ||||
| private: | ||||
|     String m_text; | ||||
|     GTextRange m_range; | ||||
| }; | ||||
| 
 | ||||
| class RemoveTextCommand : public GTextDocumentUndoCommand { | ||||
| public: | ||||
|     RemoveTextCommand(GTextDocument&, const String&, const GTextRange&); | ||||
|     virtual void undo() override; | ||||
|     virtual void redo() override; | ||||
| 
 | ||||
| private: | ||||
|     String m_text; | ||||
|     GTextRange m_range; | ||||
| }; | ||||
|  |  | |||
|  | @ -60,9 +60,11 @@ public: | |||
|     bool is_readonly() const { return m_readonly; } | ||||
|     void set_readonly(bool); | ||||
| 
 | ||||
|     bool is_automatic_indentation_enabled() const { return m_automatic_indentation_enabled; } | ||||
|     virtual bool is_automatic_indentation_enabled() const final { return m_automatic_indentation_enabled; } | ||||
|     void set_automatic_indentation_enabled(bool enabled) { m_automatic_indentation_enabled = enabled; } | ||||
| 
 | ||||
|     virtual int soft_tab_width() const final { return m_soft_tab_width; } | ||||
| 
 | ||||
|     bool is_line_wrapping_enabled() const { return m_line_wrapping_enabled; } | ||||
|     void set_line_wrapping_enabled(bool); | ||||
| 
 | ||||
|  | @ -202,7 +204,7 @@ private: | |||
|     inline void execute(Args&&... args) | ||||
|     { | ||||
|         auto command = make<T>(*m_document, forward<Args>(args)...); | ||||
|         command->redo(); | ||||
|         command->execute_from(*this); | ||||
|         m_document->add_to_undo_stack(move(command)); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling