vimamsa 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.dockerignore +32 -0
- data/Dockerfile +45 -0
- data/README.md +2 -2
- data/custom_example.rb +38 -9
- data/docker_cmd.sh +7 -0
- data/exe/run_tests.rb +23 -0
- data/img/screenshot1.png +0 -0
- data/img/screenshot2.png +0 -0
- data/lib/vimamsa/actions.rb +8 -0
- data/lib/vimamsa/buffer.rb +165 -53
- data/lib/vimamsa/buffer_changetext.rb +68 -14
- data/lib/vimamsa/buffer_cursor.rb +9 -3
- data/lib/vimamsa/buffer_list.rb +14 -28
- data/lib/vimamsa/buffer_manager.rb +1 -1
- data/lib/vimamsa/conf.rb +33 -1
- data/lib/vimamsa/diff_buffer.rb +185 -0
- data/lib/vimamsa/editor.rb +149 -80
- data/lib/vimamsa/file_finder.rb +6 -2
- data/lib/vimamsa/gui.rb +330 -135
- data/lib/vimamsa/gui_dialog.rb +2 -0
- data/lib/vimamsa/gui_file_panel.rb +94 -0
- data/lib/vimamsa/gui_form_generator.rb +4 -2
- data/lib/vimamsa/gui_func_panel.rb +127 -0
- data/lib/vimamsa/gui_image.rb +2 -4
- data/lib/vimamsa/gui_menu.rb +54 -1
- data/lib/vimamsa/gui_select_window.rb +18 -6
- data/lib/vimamsa/gui_settings.rb +486 -0
- data/lib/vimamsa/gui_sourceview.rb +196 -8
- data/lib/vimamsa/gui_text.rb +0 -22
- data/lib/vimamsa/hyper_plain_text.rb +1 -0
- data/lib/vimamsa/key_actions.rb +54 -31
- data/lib/vimamsa/key_binding_tree.rb +154 -8
- data/lib/vimamsa/key_bindings_vimlike.rb +48 -35
- data/lib/vimamsa/langservp.rb +161 -7
- data/lib/vimamsa/macro.rb +54 -7
- data/lib/vimamsa/main.rb +1 -0
- data/lib/vimamsa/rbvma.rb +5 -0
- data/lib/vimamsa/string_util.rb +56 -0
- data/lib/vimamsa/test_framework.rb +137 -0
- data/lib/vimamsa/util.rb +3 -36
- data/lib/vimamsa/version.rb +1 -1
- data/modules/calculator/calculator.rb +318 -0
- data/modules/calculator/calculator_info.rb +3 -0
- data/modules/terminal/terminal.rb +140 -0
- data/modules/terminal/terminal_info.rb +3 -0
- data/run_tests.rb +89 -0
- data/styles/dark.xml +1 -1
- data/styles/molokai_edit.xml +2 -2
- data/tests/key_bindings.rb +2 -0
- data/tests/test_basic_editing.rb +86 -0
- data/tests/test_copy_paste.rb +88 -0
- data/tests/test_key_bindings.rb +152 -0
- data/tests/test_module_interface.rb +98 -0
- data/tests/test_undo.rb +201 -0
- data/vimamsa.gemspec +6 -5
- metadata +52 -14
data/lib/vimamsa/gui.rb
CHANGED
|
@@ -126,12 +126,11 @@ def gui_create_buffer(id, bufo)
|
|
|
126
126
|
|
|
127
127
|
view.register_signals()
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
ssm.set_search_path(ssm.search_path << ppath("styles/"))
|
|
131
|
-
sty = ssm.get_scheme("molokai_edit")
|
|
129
|
+
sty = load_vimamsa_scheme
|
|
132
130
|
|
|
133
131
|
buf1.highlight_matching_brackets = true
|
|
134
132
|
buf1.style_scheme = sty
|
|
133
|
+
gui_apply_color_mode(sty) if sty
|
|
135
134
|
|
|
136
135
|
view.set_highlight_current_line(true)
|
|
137
136
|
view.set_show_line_numbers(true)
|
|
@@ -148,6 +147,12 @@ def gui_create_buffer(id, bufo)
|
|
|
148
147
|
$vmag.buffers[id] = view
|
|
149
148
|
end
|
|
150
149
|
|
|
150
|
+
def gui_close_buffer(id)
|
|
151
|
+
view = vma.gui.buffers.delete(id)
|
|
152
|
+
return if view.nil?
|
|
153
|
+
view.unparent if view.parent
|
|
154
|
+
end
|
|
155
|
+
|
|
151
156
|
def gui_set_file_lang(id, lname)
|
|
152
157
|
view = $vmag.buffers[id]
|
|
153
158
|
lm = GtkSource::LanguageManager.new
|
|
@@ -159,9 +164,6 @@ def gui_set_file_lang(id, lname)
|
|
|
159
164
|
view.buffer.highlight_syntax = true
|
|
160
165
|
end
|
|
161
166
|
|
|
162
|
-
def gui_add_image(imgpath, pos)
|
|
163
|
-
end
|
|
164
|
-
|
|
165
167
|
# TODO:?
|
|
166
168
|
def gui_select_window_close(arg = nil)
|
|
167
169
|
end
|
|
@@ -183,7 +185,8 @@ def gui_set_current_buffer(id)
|
|
|
183
185
|
end
|
|
184
186
|
|
|
185
187
|
def gui_set_window_title(wtitle, subtitle = "")
|
|
186
|
-
|
|
188
|
+
wtitle = wtitle[0..150]
|
|
189
|
+
$vmag.window.title = "Vimamsa - #{wtitle}"
|
|
187
190
|
# $vmag.subtitle.markup = "<span weight='ultrabold'>#{subtitle}</span>"
|
|
188
191
|
$vmag.subtitle.markup = "<span weight='light' size='small'>#{subtitle}</span>"
|
|
189
192
|
# $vmag.window.titlebar.subtitle = subtitle #TODO:gtk4
|
|
@@ -191,7 +194,7 @@ end
|
|
|
191
194
|
|
|
192
195
|
class VMAgui
|
|
193
196
|
attr_accessor :buffers, :sw1, :sw2, :view, :buf1, :window, :delex, :statnfo, :overlay, :sws, :two_c
|
|
194
|
-
attr_reader :two_column, :windows, :subtitle, :app, :active_window
|
|
197
|
+
attr_reader :two_column, :windows, :subtitle, :app, :active_window, :action_trail_label, :file_panel, :func_panel
|
|
195
198
|
|
|
196
199
|
def initialize()
|
|
197
200
|
@two_column = false
|
|
@@ -205,6 +208,13 @@ class VMAgui
|
|
|
205
208
|
@img_resizer_active = false
|
|
206
209
|
@windows = {}
|
|
207
210
|
@app = nil
|
|
211
|
+
@entry_has_focus = false
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Called by embedded widgets (e.g. calculator entries) when a text entry
|
|
215
|
+
# gains or loses focus, so the vimamsa key handler knows to step aside.
|
|
216
|
+
def notify_entry_focus(active)
|
|
217
|
+
@entry_has_focus = active
|
|
208
218
|
end
|
|
209
219
|
|
|
210
220
|
def run
|
|
@@ -313,123 +323,163 @@ class VMAgui
|
|
|
313
323
|
end
|
|
314
324
|
|
|
315
325
|
def add_to_minibuf(msg)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
@
|
|
319
|
-
|
|
326
|
+
@minibuf_messages ||= []
|
|
327
|
+
@minibuf_messages.unshift(msg)
|
|
328
|
+
@minibuf_messages = @minibuf_messages.first(50)
|
|
329
|
+
|
|
330
|
+
@minibuf_label.label = msg
|
|
331
|
+
@minibuf_textview.buffer.text = @minibuf_messages.join("\n")
|
|
332
|
+
|
|
333
|
+
return if @minibuf_expanded
|
|
334
|
+
|
|
335
|
+
@minibuf_stack.visible_child_name = "label"
|
|
336
|
+
@minibuf_content.visible = true
|
|
337
|
+
|
|
338
|
+
@minibuf_vpane.position = @minibuf_vpane.height - 26
|
|
339
|
+
|
|
340
|
+
GLib::Source.remove(@minibuf_hide_source) if @minibuf_hide_source
|
|
341
|
+
@minibuf_hide_source = GLib::Timeout.add(7000) do
|
|
342
|
+
@minibuf_content.visible = false
|
|
343
|
+
@minibuf_hide_source = nil
|
|
344
|
+
false
|
|
345
|
+
end
|
|
320
346
|
end
|
|
321
347
|
|
|
322
|
-
def
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
348
|
+
def minibuf_toggle_expanded
|
|
349
|
+
@minibuf_expanded = !@minibuf_expanded
|
|
350
|
+
if @minibuf_expanded
|
|
351
|
+
GLib::Source.remove(@minibuf_hide_source) if @minibuf_hide_source
|
|
352
|
+
@minibuf_hide_source = nil
|
|
353
|
+
@minibuf_content.visible = true
|
|
354
|
+
@minibuf_stack.visible_child_name = "history"
|
|
355
|
+
run_as_idle proc {
|
|
356
|
+
pos = @minibuf_vpane.max_position - (@minibuf_history_height || 120)
|
|
357
|
+
@minibuf_vpane.position = [pos, 0].max
|
|
358
|
+
}
|
|
359
|
+
else
|
|
360
|
+
# Save height before collapsing so next open restores it
|
|
361
|
+
@minibuf_history_height = @minibuf_vpane.max_position - @minibuf_vpane.position
|
|
362
|
+
@minibuf_stack.visible_child_name = "label"
|
|
363
|
+
run_as_idle proc {
|
|
364
|
+
#TODO: automatic way of resizing doesn't work:
|
|
365
|
+
# h = [@minibuf_label.height, 24].max + 2
|
|
366
|
+
# @minibuf_vpane.position = @minibuf_vpane.max_position - h
|
|
367
|
+
@minibuf_vpane.position = @minibuf_vpane.height - 26
|
|
368
|
+
}
|
|
369
|
+
@minibuf_hide_source = GLib::Timeout.add(7000) do
|
|
370
|
+
@minibuf_content.visible = false
|
|
371
|
+
@minibuf_expanded = false
|
|
372
|
+
@minibuf_stack.visible_child_name = "label"
|
|
373
|
+
@minibuf_hide_source = nil
|
|
374
|
+
false
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def show_message_history
|
|
380
|
+
minibuf_toggle_expanded
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# ── editor-area helpers (delegates to @minibuf_vpane start child) ─────────
|
|
384
|
+
|
|
385
|
+
def editor_area
|
|
386
|
+
@minibuf_vpane.start_child
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def set_editor_area(w)
|
|
390
|
+
@minibuf_vpane.set_start_child(w)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def init_minibuffer
|
|
394
|
+
@minibuf_messages = []
|
|
395
|
+
@minibuf_expanded = false
|
|
396
|
+
@minibuf_history_height = 120
|
|
397
|
+
|
|
398
|
+
css = "label.minibuf, textview.minibuf { color: #cdd6f4; font-family: Monospace; font-size: 10pt; padding: 3px 8px; background-color: #1e1e2e; }"
|
|
340
399
|
provider = Gtk::CssProvider.new
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
view
|
|
344
|
-
|
|
345
|
-
@
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
400
|
+
provider.load(data: css)
|
|
401
|
+
|
|
402
|
+
# Collapsed view: single line, latest message
|
|
403
|
+
@minibuf_label = Gtk::Label.new("")
|
|
404
|
+
@minibuf_label.xalign = 0.0
|
|
405
|
+
@minibuf_label.hexpand = true
|
|
406
|
+
@minibuf_label.ellipsize = Pango::EllipsizeMode::END
|
|
407
|
+
@minibuf_label.add_css_class("minibuf")
|
|
408
|
+
@minibuf_label.style_context.add_provider(provider)
|
|
409
|
+
|
|
410
|
+
# Expanded view: scrollable history (fills whatever height the pane gives)
|
|
411
|
+
@minibuf_textview = Gtk::TextView.new
|
|
412
|
+
@minibuf_textview.editable = false
|
|
413
|
+
@minibuf_textview.cursor_visible = false
|
|
414
|
+
@minibuf_textview.wrap_mode = :word_char
|
|
415
|
+
@minibuf_textview.add_css_class("minibuf")
|
|
416
|
+
@minibuf_textview.style_context.add_provider(provider)
|
|
417
|
+
@minibuf_textview.vexpand = true
|
|
418
|
+
|
|
419
|
+
scroll = Gtk::ScrolledWindow.new
|
|
420
|
+
scroll.set_policy(:never, :automatic)
|
|
421
|
+
scroll.set_child(@minibuf_textview)
|
|
422
|
+
scroll.vexpand = true
|
|
423
|
+
|
|
424
|
+
@minibuf_stack = Gtk::Stack.new
|
|
425
|
+
@minibuf_stack.vhomogeneous = false
|
|
426
|
+
@minibuf_stack.transition_type = :crossfade
|
|
427
|
+
@minibuf_stack.transition_duration = 100
|
|
428
|
+
@minibuf_stack.add_named(@minibuf_label, "label")
|
|
429
|
+
@minibuf_stack.add_named(scroll, "history")
|
|
430
|
+
|
|
431
|
+
@minibuf_content = Gtk::Box.new(:vertical, 0)
|
|
432
|
+
@minibuf_content.append(Gtk::Separator.new(:horizontal))
|
|
433
|
+
@minibuf_content.append(@minibuf_stack)
|
|
434
|
+
@minibuf_content.visible = false # hidden until first message
|
|
435
|
+
|
|
436
|
+
# Vertical pane: editor fills top, minibuffer sits at bottom, draggable
|
|
437
|
+
editor_w = @windows[1][:overlay]
|
|
438
|
+
@vbox.remove(editor_w)
|
|
439
|
+
|
|
440
|
+
@minibuf_vpane = Gtk::Paned.new(:vertical)
|
|
441
|
+
@minibuf_vpane.vexpand = true
|
|
442
|
+
@minibuf_vpane.hexpand = true
|
|
443
|
+
@minibuf_vpane.resize_start_child = true # editor absorbs window resize
|
|
444
|
+
@minibuf_vpane.resize_end_child = false # minibuffer keeps its height
|
|
445
|
+
@minibuf_vpane.shrink_end_child = true # allow fully collapsing minibuffer
|
|
446
|
+
@minibuf_vpane.set_start_child(editor_w)
|
|
447
|
+
@minibuf_vpane.set_end_child(@minibuf_content)
|
|
448
|
+
|
|
449
|
+
@vbox.attach(@minibuf_vpane, 0, 2, 2, 1)
|
|
450
|
+
@minibuf_hide_source = nil
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def make_header_button(action_id, icon, cb)
|
|
454
|
+
act = Gio::SimpleAction.new(action_id)
|
|
455
|
+
@app.add_action(act)
|
|
456
|
+
act.signal_connect("activate") { |_a, _p| cb.call }
|
|
457
|
+
btn = Gtk::Button.new
|
|
458
|
+
btn.set_child(Gtk::Image.new(icon_name: icon))
|
|
459
|
+
btn.action_name = "app.#{action_id}"
|
|
460
|
+
btn
|
|
349
461
|
end
|
|
350
462
|
|
|
351
|
-
#TODO: implement in gtk4
|
|
352
463
|
def init_header_bar()
|
|
353
464
|
header = Gtk::HeaderBar.new
|
|
354
465
|
@header = header
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
#
|
|
371
|
-
|
|
372
|
-
# image = Gtk::Image.new(:icon => icon, :size => :button)
|
|
373
|
-
# button.add(image)
|
|
374
|
-
# header.append(button)
|
|
375
|
-
|
|
376
|
-
button = Gtk::Button.new
|
|
377
|
-
icon = Gio::ThemedIcon.new("document-open-symbolic")
|
|
378
|
-
image = Gtk::Image.new(:icon => icon, :size => :button)
|
|
379
|
-
button.add(image)
|
|
380
|
-
header.append(button)
|
|
381
|
-
|
|
382
|
-
button.signal_connect "clicked" do |_widget|
|
|
383
|
-
open_file_dialog
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
button = Gtk::Button.new
|
|
387
|
-
icon = Gio::ThemedIcon.new("document-save-symbolic")
|
|
388
|
-
image = Gtk::Image.new(:icon => icon, :size => :button)
|
|
389
|
-
button.add(image)
|
|
390
|
-
header.append(button)
|
|
391
|
-
button.signal_connect "clicked" do |_widget|
|
|
392
|
-
buf.save
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
button = Gtk::Button.new
|
|
396
|
-
icon = Gio::ThemedIcon.new("document-new-symbolic")
|
|
397
|
-
image = Gtk::Image.new(:icon => icon, :size => :button)
|
|
398
|
-
button.add(image)
|
|
399
|
-
header.append(button)
|
|
400
|
-
button.signal_connect "clicked" do |_widget|
|
|
401
|
-
create_new_file
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
box = Gtk::Box.new(:horizontal, 0)
|
|
405
|
-
box.style_context.add_class("linked")
|
|
406
|
-
|
|
407
|
-
button = Gtk::Button.new
|
|
408
|
-
image = Gtk::Image.new(:icon_name => "pan-start-symbolic", :size => :button)
|
|
409
|
-
button.add(image)
|
|
410
|
-
box.add(button)
|
|
411
|
-
button.signal_connect "clicked" do |_widget|
|
|
412
|
-
history_switch_backwards
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
button = Gtk::Button.new
|
|
416
|
-
image = Gtk::Image.new(:icon_name => "pan-end-symbolic", :size => :button)
|
|
417
|
-
button.add(image)
|
|
418
|
-
box.add(button)
|
|
419
|
-
button.signal_connect "clicked" do |_widget|
|
|
420
|
-
history_switch_forwards
|
|
421
|
-
end
|
|
422
|
-
|
|
423
|
-
button = Gtk::Button.new
|
|
424
|
-
icon = Gio::ThemedIcon.new("window-close-symbolic")
|
|
425
|
-
image = Gtk::Image.new(:icon => icon, :size => :button)
|
|
426
|
-
button.add(image)
|
|
427
|
-
box.add(button)
|
|
428
|
-
button.signal_connect "clicked" do |_widget|
|
|
429
|
-
bufs.close_current_buffer
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
header.pack_start(box)
|
|
466
|
+
|
|
467
|
+
file_box = Gtk::Box.new(:horizontal, 0)
|
|
468
|
+
file_box.style_context.add_class("linked")
|
|
469
|
+
file_box.append(make_header_button("hdr-open", "document-open-symbolic", proc { open_file_dialog }))
|
|
470
|
+
file_box.append(make_header_button("hdr-save", "document-save-symbolic", proc { buf.save }))
|
|
471
|
+
file_box.append(make_header_button("hdr-new", "document-new-symbolic", proc { create_new_file }))
|
|
472
|
+
header.pack_start(file_box)
|
|
473
|
+
|
|
474
|
+
nav_box = Gtk::Box.new(:horizontal, 0)
|
|
475
|
+
nav_box.style_context.add_class("linked")
|
|
476
|
+
nav_box.append(make_header_button("hdr-prev", "pan-start-symbolic", proc { history_switch_backwards }))
|
|
477
|
+
nav_box.append(make_header_button("hdr-next", "pan-end-symbolic", proc { history_switch_forwards }))
|
|
478
|
+
nav_box.append(make_header_button("hdr-close", "window-close-symbolic", proc { bufs.close_current_buffer }))
|
|
479
|
+
header.pack_start(nav_box)
|
|
480
|
+
|
|
481
|
+
# header.pack_end()
|
|
482
|
+
|
|
433
483
|
@window.titlebar = header
|
|
434
484
|
end
|
|
435
485
|
|
|
@@ -475,6 +525,10 @@ class VMAgui
|
|
|
475
525
|
@window.add_controller(press)
|
|
476
526
|
|
|
477
527
|
press.signal_connect "key-pressed" do |gesture, keyval, keycode, y|
|
|
528
|
+
# Step aside when a text entry widget (e.g. calculator var field) has focus.
|
|
529
|
+
# @entry_has_focus is set explicitly via notify_entry_focus by those widgets.
|
|
530
|
+
next false if @entry_has_focus
|
|
531
|
+
next false if @kbd_passthrough
|
|
478
532
|
name = Gdk::Keyval.to_name(keyval)
|
|
479
533
|
uki = Gdk::Keyval.to_unicode(keyval)
|
|
480
534
|
keystr = uki.chr("UTF-8")
|
|
@@ -503,6 +557,8 @@ class VMAgui
|
|
|
503
557
|
end
|
|
504
558
|
|
|
505
559
|
press.signal_connect "key-released" do |gesture, keyval, keycode, y|
|
|
560
|
+
next false if @entry_has_focus
|
|
561
|
+
next false if @kbd_passthrough
|
|
506
562
|
name = Gdk::Keyval.to_name(keyval)
|
|
507
563
|
uki = Gdk::Keyval.to_unicode(keyval)
|
|
508
564
|
keystr = uki.chr("UTF-8")
|
|
@@ -565,11 +621,16 @@ class VMAgui
|
|
|
565
621
|
@window = Gtk::ApplicationWindow.new(app)
|
|
566
622
|
@window.set_application(app)
|
|
567
623
|
|
|
624
|
+
@window.signal_connect("close-request") do
|
|
625
|
+
vma.shutdown
|
|
626
|
+
true # prevent default destroy; shutdown->gui.quit handles it
|
|
627
|
+
end
|
|
628
|
+
|
|
568
629
|
@window.title = "Multiple Views"
|
|
569
630
|
@vpaned = Gtk::Paned.new(:vertical)
|
|
570
631
|
|
|
571
632
|
@vbox = Gtk::Grid.new()
|
|
572
|
-
@window.
|
|
633
|
+
@window.set_child(@vbox)
|
|
573
634
|
|
|
574
635
|
Thread.new {
|
|
575
636
|
GLib::Idle.add(proc { debug_idle_func })
|
|
@@ -589,9 +650,9 @@ class VMAgui
|
|
|
589
650
|
motion_controller.signal_connect("motion") do |controller, x, y|
|
|
590
651
|
# label.set_text("Mouse at: (%.1f, %.1f)" % [x, y])
|
|
591
652
|
# puts "MOVE #{x} #{y}"
|
|
592
|
-
|
|
653
|
+
|
|
593
654
|
# Cursor vanishes when hovering over menubar
|
|
594
|
-
draw_cursor_bug_workaround if y < 30
|
|
655
|
+
draw_cursor_bug_workaround if y < 30
|
|
595
656
|
@last_cursor = [x, y]
|
|
596
657
|
@cursor_move_time = Time.now
|
|
597
658
|
end
|
|
@@ -628,13 +689,28 @@ class VMAgui
|
|
|
628
689
|
init_minibuffer
|
|
629
690
|
|
|
630
691
|
menubar = Gio::Menu.new
|
|
631
|
-
app.menubar = menubar
|
|
632
|
-
@window.show_menubar = true
|
|
633
|
-
|
|
634
692
|
@menubar = menubar
|
|
635
693
|
|
|
694
|
+
# TODO: Doesn't work, why?:
|
|
695
|
+
# menubar_bar = Gtk::PopoverMenuBar.new(menu_model: menubar)
|
|
696
|
+
|
|
697
|
+
menubar_bar = Gtk::PopoverMenuBar.new()
|
|
698
|
+
menubar_bar.set_menu_model(menubar)
|
|
699
|
+
|
|
700
|
+
menubar_bar.hexpand = true
|
|
701
|
+
@action_trail_label = Gtk::Label.new("")
|
|
702
|
+
@action_trail_label.add_css_class("action-trail")
|
|
703
|
+
menubar_row = Gtk::Box.new(:horizontal, 0)
|
|
704
|
+
menubar_row.append(menubar_bar)
|
|
705
|
+
menubar_row.append(@action_trail_label)
|
|
706
|
+
@vbox.attach(menubar_row, 0, 0, 2, 1)
|
|
707
|
+
|
|
636
708
|
@active_window = @windows[1]
|
|
637
709
|
|
|
710
|
+
init_header_bar
|
|
711
|
+
file_panel_init
|
|
712
|
+
func_panel_init
|
|
713
|
+
|
|
638
714
|
@window.show
|
|
639
715
|
|
|
640
716
|
surface = @window.native.surface
|
|
@@ -670,7 +746,9 @@ class VMAgui
|
|
|
670
746
|
min-width: 15px;
|
|
671
747
|
}
|
|
672
748
|
|
|
673
|
-
popover background > contents { padding: 8px; border-radius: 20px; }
|
|
749
|
+
popover background > contents { padding: 8px; border-radius: 20px; }
|
|
750
|
+
|
|
751
|
+
label.action-trail { font-family: monospace; font-size: 10pt; margin-right: 8px; color: #aaaaaa; }
|
|
674
752
|
")
|
|
675
753
|
@window.style_context.add_provider(prov)
|
|
676
754
|
|
|
@@ -700,7 +778,11 @@ class VMAgui
|
|
|
700
778
|
end
|
|
701
779
|
|
|
702
780
|
def init_menu
|
|
703
|
-
Vimamsa::Menu.new(@menubar, @app)
|
|
781
|
+
@menu = Vimamsa::Menu.new(@menubar, @app)
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def menu
|
|
785
|
+
@menu
|
|
704
786
|
end
|
|
705
787
|
|
|
706
788
|
def toggle_two_column
|
|
@@ -724,9 +806,13 @@ class VMAgui
|
|
|
724
806
|
@pane.set_start_child(nil)
|
|
725
807
|
@pane.set_end_child(nil)
|
|
726
808
|
|
|
727
|
-
@
|
|
728
|
-
|
|
729
|
-
|
|
809
|
+
if @func_panel_shown
|
|
810
|
+
@func_panel_pane.set_end_child(w1[:overlay])
|
|
811
|
+
elsif @file_panel_shown
|
|
812
|
+
@file_panel_pane.set_end_child(w1[:overlay])
|
|
813
|
+
else
|
|
814
|
+
set_editor_area(w1[:overlay])
|
|
815
|
+
end
|
|
730
816
|
@two_column = false
|
|
731
817
|
end
|
|
732
818
|
|
|
@@ -776,14 +862,24 @@ class VMAgui
|
|
|
776
862
|
w1 = @windows[1]
|
|
777
863
|
w2 = @windows[2]
|
|
778
864
|
|
|
779
|
-
# Remove overlay from
|
|
865
|
+
# Remove overlay from its current parent and add the Gtk::Paned instead
|
|
780
866
|
@pane = Gtk::Paned.new(:horizontal)
|
|
781
|
-
@
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
@
|
|
867
|
+
if @func_panel_shown
|
|
868
|
+
@func_panel_pane.set_end_child(nil)
|
|
869
|
+
@pane.set_start_child(w2[:overlay])
|
|
870
|
+
@pane.set_end_child(w1[:overlay])
|
|
871
|
+
@func_panel_pane.set_end_child(@pane)
|
|
872
|
+
elsif @file_panel_shown
|
|
873
|
+
@file_panel_pane.set_end_child(nil)
|
|
874
|
+
@pane.set_start_child(w2[:overlay])
|
|
875
|
+
@pane.set_end_child(w1[:overlay])
|
|
876
|
+
@file_panel_pane.set_end_child(@pane)
|
|
877
|
+
else
|
|
878
|
+
@minibuf_vpane.set_start_child(nil) # unparent w1[:overlay] before re-parenting
|
|
879
|
+
@pane.set_start_child(w2[:overlay])
|
|
880
|
+
@pane.set_end_child(w1[:overlay])
|
|
881
|
+
set_editor_area(@pane)
|
|
882
|
+
end
|
|
787
883
|
|
|
788
884
|
w2[:sw].show
|
|
789
885
|
@two_column = true
|
|
@@ -940,4 +1036,103 @@ class VMAgui
|
|
|
940
1036
|
# view.place_cursor_onscreen #TODO: needed?
|
|
941
1037
|
view.draw_cursor
|
|
942
1038
|
end
|
|
1039
|
+
|
|
1040
|
+
def file_panel_init
|
|
1041
|
+
@file_panel = FileTreePanel.new
|
|
1042
|
+
@file_panel_shown = false
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
def file_panel_refresh
|
|
1046
|
+
return unless @file_panel_shown
|
|
1047
|
+
@file_panel.refresh
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
def show_file_panel
|
|
1051
|
+
return if @file_panel_shown
|
|
1052
|
+
# If func panel is shown it sits in minibuf_vpane; wrap it too
|
|
1053
|
+
inner = if @func_panel_shown
|
|
1054
|
+
@func_panel_pane
|
|
1055
|
+
elsif @two_column
|
|
1056
|
+
@pane
|
|
1057
|
+
else
|
|
1058
|
+
@windows[1][:overlay]
|
|
1059
|
+
end
|
|
1060
|
+
@minibuf_vpane.set_start_child(nil) # unparent inner before re-parenting
|
|
1061
|
+
@file_panel_pane = Gtk::Paned.new(:horizontal)
|
|
1062
|
+
@file_panel_pane.hexpand = true
|
|
1063
|
+
@file_panel_pane.vexpand = true
|
|
1064
|
+
@file_panel_pane.set_start_child(@file_panel.widget)
|
|
1065
|
+
@file_panel_pane.set_end_child(inner)
|
|
1066
|
+
@file_panel_pane.set_position(180)
|
|
1067
|
+
set_editor_area(@file_panel_pane)
|
|
1068
|
+
@file_panel_shown = true
|
|
1069
|
+
@file_panel.refresh
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
def hide_file_panel
|
|
1073
|
+
return unless @file_panel_shown
|
|
1074
|
+
inner = @file_panel_pane.end_child
|
|
1075
|
+
@file_panel_pane.set_start_child(nil)
|
|
1076
|
+
@file_panel_pane.set_end_child(nil)
|
|
1077
|
+
set_editor_area(inner)
|
|
1078
|
+
@file_panel_shown = false
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
def toggle_file_panel
|
|
1082
|
+
@file_panel_shown ? hide_file_panel : show_file_panel
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
def func_panel_init
|
|
1086
|
+
@func_panel = FuncPanel.new
|
|
1087
|
+
@func_panel_shown = false
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
def func_panel_refresh
|
|
1091
|
+
return unless @func_panel_shown
|
|
1092
|
+
@func_panel.refresh
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
def show_func_panel
|
|
1096
|
+
return if @func_panel_shown
|
|
1097
|
+
if @file_panel_shown
|
|
1098
|
+
inner = @file_panel_pane.end_child
|
|
1099
|
+
@file_panel_pane.set_end_child(nil)
|
|
1100
|
+
elsif @two_column
|
|
1101
|
+
inner = @pane
|
|
1102
|
+
@minibuf_vpane.set_start_child(nil)
|
|
1103
|
+
else
|
|
1104
|
+
inner = @windows[1][:overlay]
|
|
1105
|
+
@minibuf_vpane.set_start_child(nil)
|
|
1106
|
+
end
|
|
1107
|
+
@func_panel_pane = Gtk::Paned.new(:horizontal)
|
|
1108
|
+
@func_panel_pane.hexpand = true
|
|
1109
|
+
@func_panel_pane.vexpand = true
|
|
1110
|
+
@func_panel_pane.set_start_child(@func_panel.widget)
|
|
1111
|
+
@func_panel_pane.set_end_child(inner)
|
|
1112
|
+
@func_panel_pane.set_position(160)
|
|
1113
|
+
if @file_panel_shown
|
|
1114
|
+
@file_panel_pane.set_end_child(@func_panel_pane)
|
|
1115
|
+
else
|
|
1116
|
+
set_editor_area(@func_panel_pane)
|
|
1117
|
+
end
|
|
1118
|
+
@func_panel_shown = true
|
|
1119
|
+
@func_panel.refresh
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
def hide_func_panel
|
|
1123
|
+
return unless @func_panel_shown
|
|
1124
|
+
inner = @func_panel_pane.end_child
|
|
1125
|
+
@func_panel_pane.set_start_child(nil)
|
|
1126
|
+
@func_panel_pane.set_end_child(nil)
|
|
1127
|
+
if @file_panel_shown
|
|
1128
|
+
@file_panel_pane.set_end_child(inner)
|
|
1129
|
+
else
|
|
1130
|
+
set_editor_area(inner)
|
|
1131
|
+
end
|
|
1132
|
+
@func_panel_shown = false
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
def toggle_func_panel
|
|
1136
|
+
@func_panel_shown ? hide_func_panel : show_func_panel
|
|
1137
|
+
end
|
|
943
1138
|
end
|
data/lib/vimamsa/gui_dialog.rb
CHANGED
|
@@ -39,6 +39,8 @@ end
|
|
|
39
39
|
class OneInputAction
|
|
40
40
|
def initialize(main_window, title, field_label, button_title, callback, opt = {})
|
|
41
41
|
@window = Gtk::Window.new()
|
|
42
|
+
@window.set_transient_for($vmag.window) if $vmag&.window
|
|
43
|
+
@window.modal = true
|
|
42
44
|
# @window.screen = main_window.screen
|
|
43
45
|
@window.title = ""
|
|
44
46
|
# @window.width_request = 800
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
class FileTreePanel
|
|
2
|
+
COL_LABEL = 0
|
|
3
|
+
COL_BUF_ID = 1 # 0 = folder row (not selectable)
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@store = Gtk::TreeStore.new(String, Integer)
|
|
7
|
+
@tree = Gtk::TreeView.new(@store)
|
|
8
|
+
@tree.headers_visible = false
|
|
9
|
+
@tree.activate_on_single_click = true
|
|
10
|
+
@tree.level_indentation = 7
|
|
11
|
+
|
|
12
|
+
renderer = Gtk::CellRendererText.new
|
|
13
|
+
renderer.ellipsize = Pango::EllipsizeMode::START
|
|
14
|
+
col = Gtk::TreeViewColumn.new("", renderer, text: COL_LABEL)
|
|
15
|
+
col.expand = true
|
|
16
|
+
@tree.append_column(col)
|
|
17
|
+
|
|
18
|
+
@tree.signal_connect("row-activated") do |tv, path, _col|
|
|
19
|
+
iter = @store.get_iter(path)
|
|
20
|
+
next if iter.nil?
|
|
21
|
+
buf_id = iter[COL_BUF_ID]
|
|
22
|
+
next if buf_id.nil? || buf_id == 0
|
|
23
|
+
vma.buffers.set_current_buffer(buf_id)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@context_menu = nil
|
|
27
|
+
rightclick = Gtk::GestureClick.new
|
|
28
|
+
rightclick.button = 3
|
|
29
|
+
@tree.add_controller(rightclick)
|
|
30
|
+
rightclick.signal_connect("pressed") do |gesture, n_press, x, y|
|
|
31
|
+
result = @tree.get_path_at_pos(x.to_i, y.to_i)
|
|
32
|
+
next unless result
|
|
33
|
+
iter = @store.get_iter(result[0])
|
|
34
|
+
next unless iter
|
|
35
|
+
buf_id = iter[COL_BUF_ID]
|
|
36
|
+
next unless buf_id && buf_id != 0
|
|
37
|
+
@context_buf_id = buf_id
|
|
38
|
+
show_context_menu(x, y)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@sw = Gtk::ScrolledWindow.new
|
|
42
|
+
@sw.set_policy(:never, :automatic)
|
|
43
|
+
@sw.set_child(@tree)
|
|
44
|
+
@sw.set_size_request(180, -1)
|
|
45
|
+
@sw.vexpand = true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def widget
|
|
49
|
+
@sw
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def init_context_menu
|
|
53
|
+
act = Gio::SimpleAction.new("fp_close_buffer")
|
|
54
|
+
vma.gui.app.add_action(act)
|
|
55
|
+
act.signal_connect("activate") { vma.buffers.close_buffer(@context_buf_id) if @context_buf_id }
|
|
56
|
+
@context_menu = Gtk::PopoverMenu.new
|
|
57
|
+
@context_menu.set_parent(@tree)
|
|
58
|
+
@context_menu.has_arrow = false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def show_context_menu(x, y)
|
|
62
|
+
init_context_menu if @context_menu.nil?
|
|
63
|
+
menu = Gio::Menu.new
|
|
64
|
+
menu.append("Close file", "app.fp_close_buffer")
|
|
65
|
+
@context_menu.set_menu_model(menu)
|
|
66
|
+
@context_menu.set_pointing_to(Gdk::Rectangle.new(x.to_i, y.to_i, 1, 1))
|
|
67
|
+
@context_menu.popup
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def refresh
|
|
71
|
+
@store.clear
|
|
72
|
+
bh = {}
|
|
73
|
+
vma.buffers.list.each do |b|
|
|
74
|
+
dname = b.fname ? File.dirname(b.fname) : "*"
|
|
75
|
+
bname = b.fname ? File.basename(b.fname) : (b.list_str || "(untitled)")
|
|
76
|
+
bh[dname] ||= []
|
|
77
|
+
bh[dname] << { bname: bname, buf: b }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
bh.keys.sort.each do |dname|
|
|
81
|
+
dir_iter = @store.append(nil)
|
|
82
|
+
dir_iter[COL_LABEL] = "📂 #{tilde_path(dname)}"
|
|
83
|
+
dir_iter[COL_BUF_ID] = 0
|
|
84
|
+
bh[dname].sort_by { |x| x[:bname] }.each do |bnfo|
|
|
85
|
+
active_mark = bnfo[:buf].is_active? ? "● " : " "
|
|
86
|
+
file_iter = @store.append(dir_iter)
|
|
87
|
+
file_iter[COL_LABEL] = "#{active_mark}#{bnfo[:bname]}"
|
|
88
|
+
file_iter[COL_BUF_ID] = bnfo[:buf].id
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
@tree.expand_all
|
|
93
|
+
end
|
|
94
|
+
end
|