glimmer-cs-gladiator 0.8.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,24 @@
1
+ # Copyright (c) 2020-2022 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
1
22
  module Glimmer
2
23
  class Gladiator
3
24
  class ProgressShell
@@ -15,6 +36,7 @@ module Glimmer
15
36
  }
16
37
 
17
38
  text 'Gladiator'
39
+ image ICON
18
40
 
19
41
  label(:center) {
20
42
  text progress_text
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020-2021 Andy Maleh
1
+ # Copyright (c) 2020-2022 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -196,6 +196,8 @@ module Glimmer
196
196
  if file.selection_count.to_i == 0
197
197
  verify_event.text += file.current_line_indentation
198
198
  end
199
+ # TODO implement this to borrowed line of code from Glimmer Meta-Sample
200
+ # verify_event.text += ' '*2 if line.strip.end_with?('{') || line.strip.match(/do[ ]+([|][^|]+[|])?$/) || line.start_with?('class') || line.start_with?('module') || line.strip.start_with?('def')
199
201
  when "\t"
200
202
  Command.do(file, :indent!)
201
203
  verify_event.doit = false
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020-2021 Andy Maleh
1
+ # Copyright (c) 2020-2022 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -96,11 +96,12 @@ module Glimmer
96
96
  ## Uncomment before_body block to pre-initialize variables to use in body
97
97
  #
98
98
  #
99
- before_body {
99
+ before_body do
100
+ @@quitting = false
100
101
  # TODO consider doing loading project files after displaying the GUI instead of holding it up before
101
- project_dir #pre-initialize directory
102
- TOPLEVEL_BINDING.receiver.send(:at_exit) do
103
- project_dir.selected_child&.write_raw_dirty_content
102
+ project_dir unless app_mode? #pre-initialize directory
103
+ TOPLEVEL_BINDING.receiver.send(:trap, "SIGINT") do |signal|
104
+ quit
104
105
  end
105
106
  Display.setAppName('Gladiator')
106
107
  Display.setAppVersion(VERSION)
@@ -108,20 +109,12 @@ module Glimmer
108
109
  unless defined?(@@display)
109
110
  @@display = display {
110
111
  # TODO look into why a weird java dialog comes up on about (maybe a non-issue once packaged)
111
- on_about {
112
- display_about_dialog
113
- }
114
- on_quit {
115
- display.swt_display.shells.each { |shell|
116
- gladiator = shell.get_data('custom_shell')
117
- gladiator.project_dir.selected_child&.write_dirty_content
118
- shell.close
119
- }
120
- }
121
- on_swt_keydown { |key_event|
112
+ on_about { display_about_dialog }
113
+ on_quit { quit }
114
+ on_swt_keydown do |key_event|
122
115
  focused_gladiator = display.focus_control.shell&.get_data('custom_shell')
123
- focused_gladiator.handle_display_shortcut(key_event) if !focused_gladiator.nil? && key_event.widget.shell == focused_gladiator&.swt_widget
124
- }
116
+ focused_gladiator.handle_display_shortcut(key_event) if !focused_gladiator.nil? && focused_gladiator.is_a?(Glimmer::Gladiator) && key_event.widget.shell == focused_gladiator&.swt_widget
117
+ end
125
118
  }
126
119
  end
127
120
 
@@ -132,124 +125,128 @@ module Glimmer
132
125
  @config = {}
133
126
  load_config_ignore_paths
134
127
  end
135
- }
128
+ end
136
129
 
137
130
  ## Uncomment after_body block to setup observers for widgets in body
138
131
  #
139
- after_body {
140
- observe(project_dir, 'children') do
141
- @file_explorer_tree.select_tree_item unless Gladiator.startup
142
- end
143
- observe(project_dir, 'selected_child') do |selected_file|
144
- if selected_file
145
- if Gladiator.drag && !@tab_folder2
146
- self.tab_folder1 = current_tab_folder
147
- @tab_folder_sash_form.content {
148
- self.current_tab_folder = self.tab_folder2 = text_editor_group_tab_folder
149
- @current_tab_folder.swt_widget.setData('proxy', @current_tab_folder)
150
- }
151
- body_root.pack_same_size
152
- end
132
+ after_body do
133
+ unless app_mode?
134
+ observe(project_dir, 'children') do
153
135
  @file_explorer_tree.select_tree_item unless Gladiator.startup
154
- found_tab_item = selected_tab_item
155
- if found_tab_item
156
- @current_tab_folder.swt_widget.setSelection(found_tab_item)
157
- @current_tab_item = found_tab_item.getData('proxy')
158
- @current_text_editor = found_tab_item.getData('text_editor') unless found_tab_item.getData('text_editor').nil?
159
- @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
160
- else
161
- begin
162
- @current_tab_folder.content {
163
- @current_tab_item = tab_item { |the_tab_item|
164
- text selected_file.name
165
- fill_layout(:horizontal) {
166
- margin_width 0
167
- margin_height 0
168
- }
169
- tab_folder = nil
170
- the_text_editor = nil
171
- the_tab_item.content {
172
- @current_text_editor = the_text_editor = text_editor(project_dir: project_dir, file: selected_file) {
173
- layout_data :fill, :fill, true, true
136
+ end
137
+ observe(project_dir, 'selected_child') do |selected_file|
138
+ if selected_file
139
+ if Gladiator.drag && !@tab_folder2
140
+ self.tab_folder1 = current_tab_folder
141
+ @tab_folder_sash_form.content {
142
+ self.current_tab_folder = self.tab_folder2 = text_editor_group_tab_folder
143
+ @current_tab_folder.swt_widget.setData('proxy', @current_tab_folder)
144
+ }
145
+ body_root.pack_same_size
146
+ end
147
+ @file_explorer_tree.select_tree_item unless Gladiator.startup
148
+ found_tab_item = selected_tab_item
149
+ if found_tab_item
150
+ @current_tab_folder.swt_widget.setSelection(found_tab_item)
151
+ @current_tab_item = found_tab_item.getData('proxy')
152
+ @current_text_editor = found_tab_item.getData('text_editor') unless found_tab_item.getData('text_editor').nil?
153
+ @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
154
+ else
155
+ begin
156
+ @current_tab_folder.content {
157
+ @current_tab_item = tab_item { |the_tab_item|
158
+ text selected_file.name
159
+ fill_layout(:horizontal) {
160
+ margin_width 0
161
+ margin_height 0
174
162
  }
175
- @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
176
- the_tab_item.swt_tab_item.setData('text_editor', @current_text_editor)
177
- @current_text_editor.text_proxy.content {
178
- on_focus_gained {
179
- tab_folder = the_text_editor.swt_widget.getParent.getParent
180
- self.current_tab_folder = tab_folder.getData('proxy')
181
- @current_tab_item = the_tab_item
182
- @current_text_editor = the_text_editor
183
- @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
184
- @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
185
- project_dir.selected_child = @current_tab_item.swt_tab_item.getData('file')
163
+ tab_folder = nil
164
+ the_text_editor = nil
165
+ the_tab_item.content {
166
+ @current_text_editor = the_text_editor = text_editor(project_dir: project_dir, file: selected_file) {
167
+ layout_data :fill, :fill, true, true
168
+ }
169
+ @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
170
+ the_tab_item.swt_tab_item.setData('text_editor', @current_text_editor)
171
+ @current_text_editor.text_proxy.content {
172
+ on_focus_gained {
173
+ tab_folder = the_text_editor.swt_widget.getParent.getParent
174
+ self.current_tab_folder = tab_folder.getData('proxy')
175
+ @current_tab_item = the_tab_item
176
+ @current_text_editor = the_text_editor
177
+ @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
178
+ @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
179
+ project_dir.selected_child = @current_tab_item.swt_tab_item.getData('file')
180
+ }
186
181
  }
187
182
  }
183
+
184
+ on_swt_show do
185
+ @current_tab_item = the_tab_item
186
+ @current_text_editor = the_text_editor
187
+ self.current_tab_folder = @current_tab_item.swt_widget.getParent.getData('proxy')
188
+ @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
189
+ @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
190
+ project_dir.selected_child = selected_file
191
+ @current_text_editor&.load_content
192
+ @current_text_editor&.text_widget&.setFocus
193
+ save_config unless selected_file.nil?
194
+ end
195
+
196
+ on_widget_disposed do
197
+ project_dir.selected_child&.write_dirty_content
198
+ tab_item_file = the_tab_item.swt_tab_item.get_data('file')
199
+ tab_item_file.close if !@@quitting && (@tab_folder1 != @current_tab_folder && !@tab_folder1&.items&.detect {|ti| ti.get_data('file') == tab_item_file}) || (@tab_folder2 != @current_tab_folder && !@tab_folder2&.items&.detect {|ti| ti.get_data('file') == tab_item_file})
200
+ end
188
201
  }
189
- on_swt_show {
190
- @current_tab_item = the_tab_item
191
- @current_text_editor = the_text_editor
192
- self.current_tab_folder = @current_tab_item.swt_widget.getParent.getData('proxy')
193
- @current_tab_folder.swt_widget.setData('selected_tab_item', @current_tab_item)
194
- @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
195
- project_dir.selected_child = selected_file
196
- @current_text_editor&.load_content
197
- @current_text_editor&.text_widget&.setFocus
198
- save_config unless selected_file.nil?
199
- }
200
- on_widget_disposed {
201
- project_dir.selected_child&.write_dirty_content
202
- tab_item_file = the_tab_item.swt_tab_item.get_data('file')
203
- tab_item_file.close unless [@tab_folder1, @tab_folder2].compact.map(&:items).flatten(1).detect {|ti| ti.get_data('file') == tab_item_file}
204
- }
202
+ @current_tab_item.swt_tab_item.setData('file_path', selected_file.path)
203
+ @current_tab_item.swt_tab_item.setData('file', selected_file)
204
+ @current_tab_item.swt_tab_item.setData('proxy', @current_tab_item)
205
205
  }
206
- @current_tab_item.swt_tab_item.setData('file_path', selected_file.path)
207
- @current_tab_item.swt_tab_item.setData('file', selected_file)
208
- @current_tab_item.swt_tab_item.setData('proxy', @current_tab_item)
209
- }
210
- @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
211
- body_root.pack_same_size
212
- rescue => e
213
- Glimmer::Config.logger.error {e.full_message}
206
+ @current_tab_folder.swt_widget.setSelection(@current_tab_item.swt_tab_item)
207
+ body_root.pack_same_size
208
+ rescue => e
209
+ Glimmer::Config.logger.error {e.full_message}
210
+ end
214
211
  end
212
+ @current_text_editor&.text_widget&.setFocus
215
213
  end
216
- @current_text_editor&.text_widget&.setFocus
217
214
  end
218
- end
219
- observe(self, 'maximized_pane') do
220
- if tab_folder2
221
- @tab_folder_sash_form.maximized_control = (current_tab_folder.swt_widget if maximized_pane?)
215
+ observe(self, 'maximized_pane') do
216
+ if tab_folder2
217
+ @tab_folder_sash_form.maximized_control = (current_tab_folder.swt_widget if maximized_pane?)
218
+ end
222
219
  end
223
- end
224
- observe(self, 'maximized_editor') do
225
- @file_area_and_editor_area_sash_form.maximized_control = (@editor_area_composite.swt_widget if maximized_editor?)
226
- if !maximized_editor?
227
- expand_navigation_expand_bar_height
228
- else
229
- collapse_navigation_expand_bar_height
220
+ observe(self, 'maximized_editor') do
221
+ @file_area_and_editor_area_sash_form.maximized_control = (@editor_area_composite.swt_widget if maximized_editor?)
222
+ if !maximized_editor?
223
+ expand_navigation_expand_bar_height
224
+ else
225
+ collapse_navigation_expand_bar_height
226
+ end
227
+ @navigation_expand_item.swt_expand_item.set_expanded !maximized_editor?
228
+ body_root.pack_same_size
229
+ async_exec { body_root.pack_same_size }
230
230
  end
231
- @navigation_expand_item.swt_expand_item.set_expanded !maximized_editor?
232
- body_root.pack_same_size
233
- async_exec { body_root.pack_same_size }
234
- end
235
- observe(project_dir, 'selected_child') do
236
- save_config
237
- end
238
- observe(project_dir, 'selected_child.caret_position') do
239
- save_config
240
- end
241
- observe(project_dir, 'selected_child.top_pixel') do
242
- save_config
231
+ observe(project_dir, 'selected_child') do
232
+ save_config
233
+ end
234
+ observe(project_dir, 'selected_child.caret_position') do
235
+ save_config
236
+ end
237
+ observe(project_dir, 'selected_child.top_pixel') do
238
+ save_config
239
+ end
240
+ load_config
243
241
  end
244
- load_config unless app_mode?
245
- }
242
+ end
246
243
 
247
244
  ## Add widget content inside custom shell body
248
245
  ## Top-most widget must be a shell or another custom shell
249
246
  #
250
247
  body {
251
248
  if app_mode?
252
- shell {
249
+ @@app_mode_shell = shell {
253
250
  text 'Gladiator'
254
251
  minimum_size 250, 250
255
252
  image ICON
@@ -284,6 +281,8 @@ module Glimmer
284
281
 
285
282
  on_shell_closed {
286
283
  project_dir.selected_child&.write_dirty_content
284
+ save_config
285
+ @paused_save_config = true
287
286
  if @tab_folder2
288
287
  current_tab_folder.swt_widget.getItems.each do |tab_item|
289
288
  tab_item.getData('proxy')&.dispose
@@ -293,10 +292,10 @@ module Glimmer
293
292
  current_tab_folder.swt_widget.getItems.each do |tab_item|
294
293
  tab_item.getData('proxy')&.dispose
295
294
  end
295
+ gladiator_shells = display.shells.select {|s| s.get_data('custom_shell')&.is_a?(Glimmer::Gladiator)}
296
+ project_dir.close unless @@quitting
296
297
  body_root.close unless current_tab_folder.swt_widget.getItems.empty?
297
- }
298
- on_widget_disposed {
299
- project_dir.selected_child&.write_dirty_content
298
+ async_exec { @@app_mode_shell.show } if defined?(@@app_mode_shell) && gladiator_shells.count <= 2
300
299
  }
301
300
  on_control_resized {
302
301
  save_config
@@ -306,6 +305,7 @@ module Glimmer
306
305
  }
307
306
  on_shell_deactivated {
308
307
  project_dir.selected_child&.write_dirty_content
308
+ save_config
309
309
  }
310
310
 
311
311
  # Menu Bar
@@ -690,7 +690,7 @@ module Glimmer
690
690
  Gladiator.drag = true
691
691
  tab_folder = event.widget.getControl
692
692
  tab_item = tab_folder.getItem(Point.new(event.x, event.y))
693
- event_data = tab_item.getData('file_path')
693
+ event_data = tab_item&.getData('file_path')
694
694
  }
695
695
  on_drag_set_data { |event|
696
696
  event.data = event_data
@@ -763,28 +763,28 @@ module Glimmer
763
763
  project_dir.selected_child&.top_pixel = @config[:top_pixel].to_i if @config[:top_pixel]
764
764
  end
765
765
  }
766
- async_exec {
766
+ async_exec do
767
767
  Gladiator.drag = false
768
768
  @progress_shell&.close
769
769
  @progress_shell = nil
770
770
  @loaded_config = true
771
- }
771
+ end
772
772
  }
773
- async_exec {
773
+ async_exec do
774
774
  Thread.new {
775
775
  all_files = open_file_paths1.to_a + open_file_paths2.to_a
776
776
  all_files.each do |file|
777
777
  project_dir.find_child_file(file)&.dirty_content
778
778
  end
779
779
  }
780
- }
780
+ end
781
781
  else
782
782
  @loaded_config = true
783
783
  end
784
784
  end
785
785
 
786
786
  def save_config
787
- return if !@loaded_config || body_root&.disposed?
787
+ return if !@loaded_config || body_root&.disposed? || @paused_save_config
788
788
  child = project_dir.selected_child
789
789
  return if child.nil?
790
790
  tab_folder1 = @tab_folder1 || @current_tab_folder
@@ -915,14 +915,23 @@ module Glimmer
915
915
  async_exec {
916
916
  @progress_shell.open
917
917
  }
918
- async_exec {
918
+ async_exec do
919
919
  gladiator(project_dir_path: selected_directory) {
920
920
  on_swt_show {
921
- body_root.close if app_mode?
921
+ @@app_mode_shell.hide if app_mode?
922
922
  @progress_shell.close
923
923
  @progress_shell = nil
924
924
  }
925
925
  }.open if selected_directory
926
+ end
927
+ end
928
+
929
+ def quit
930
+ @@quitting = true
931
+ display.shells.each { |shell|
932
+ gladiator = shell.get_data('custom_shell')
933
+ gladiator.project_dir.selected_child&.write_dirty_content unless app_mode?
934
+ shell.get_data('proxy').close
926
935
  }
927
936
  end
928
937
 
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-cs-gladiator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-08 00:00:00.000000000 Z
11
+ date: 2022-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: 4.18.4.3
19
- - - "<"
16
+ - - "~>"
20
17
  - !ruby/object:Gem::Version
21
- version: 5.0.0.0
18
+ version: 4.20.16.0
22
19
  name: glimmer-dsl-swt
23
- type: :runtime
24
20
  prerelease: false
21
+ type: :runtime
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 4.18.4.3
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: 5.0.0.0
26
+ version: 4.20.16.0
33
27
  - !ruby/object:Gem::Dependency
34
28
  requirement: !ruby/object:Gem::Requirement
35
29
  requirements:
@@ -37,8 +31,8 @@ dependencies:
37
31
  - !ruby/object:Gem::Version
38
32
  version: 1.1.1
39
33
  name: filewatcher
40
- type: :runtime
41
34
  prerelease: false
35
+ type: :runtime
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
38
  - - "~>"
@@ -51,8 +45,8 @@ dependencies:
51
45
  - !ruby/object:Gem::Version
52
46
  version: 1.3.5
53
47
  name: clipboard
54
- type: :runtime
55
48
  prerelease: false
49
+ type: :runtime
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
51
  requirements:
58
52
  - - "~>"
@@ -65,8 +59,8 @@ dependencies:
65
59
  - !ruby/object:Gem::Version
66
60
  version: 3.5.0
67
61
  name: rspec
68
- type: :development
69
62
  prerelease: false
63
+ type: :development
70
64
  version_requirements: !ruby/object:Gem::Requirement
71
65
  requirements:
72
66
  - - "~>"
@@ -79,8 +73,8 @@ dependencies:
79
73
  - !ruby/object:Gem::Version
80
74
  version: 2.3.9
81
75
  name: jeweler
82
- type: :development
83
76
  prerelease: false
77
+ type: :development
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - '='
@@ -93,13 +87,27 @@ dependencies:
93
87
  - !ruby/object:Gem::Version
94
88
  version: 2.0.5
95
89
  name: warbler
96
- type: :development
97
90
  prerelease: false
91
+ type: :development
98
92
  version_requirements: !ruby/object:Gem::Requirement
99
93
  requirements:
100
94
  - - '='
101
95
  - !ruby/object:Gem::Version
102
96
  version: 2.0.5
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 9.2.19.0
103
+ name: jruby-jars
104
+ prerelease: false
105
+ type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 9.2.19.0
103
111
  - !ruby/object:Gem::Dependency
104
112
  requirement: !ruby/object:Gem::Requirement
105
113
  requirements:
@@ -107,8 +115,8 @@ dependencies:
107
115
  - !ruby/object:Gem::Version
108
116
  version: '0'
109
117
  name: simplecov
110
- type: :development
111
118
  prerelease: false
119
+ type: :development
112
120
  version_requirements: !ruby/object:Gem::Requirement
113
121
  requirements:
114
122
  - - ">="
@@ -127,7 +135,6 @@ executables:
127
135
  - gladiator-setup
128
136
  extensions: []
129
137
  extra_rdoc_files:
130
- - CHANGELOG.md
131
138
  - LICENSE.txt
132
139
  - README.md
133
140
  files:
@@ -174,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
181
  - !ruby/object:Gem::Version
175
182
  version: '0'
176
183
  requirements: []
177
- rubygems_version: 3.0.6
184
+ rubygems_version: 3.3.6
178
185
  signing_key:
179
186
  specification_version: 4
180
187
  summary: Gladiator (Glimmer Editor) - Glimmer Custom Shell - Text Editor Built in