vimamsa 0.1.0 → 0.1.1

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.
@@ -0,0 +1,177 @@
1
+
2
+ def gui_find_macro_update_callback(search_str = "")
3
+ puts "gui_find_macro_update_callback: #{search_str}"
4
+ heystack = $macro.named_macros
5
+ return [] if heystack.empty?
6
+ $macro_search_list = []
7
+ files = heystack.keys.sort.collect { |x| [x, 0] }
8
+
9
+ if (search_str.size > 1)
10
+ files = fuzzy_filter(search_str, heystack.keys, 40)
11
+ end
12
+ $macro_search_list = files
13
+ return files
14
+ end
15
+
16
+ def gui_find_macro_select_callback(search_str, idx)
17
+ puts "gui_find_macro_select_callback"
18
+ selected = $macro_search_list[idx]
19
+ m = $macro.named_macros[selected[0]].clone
20
+ puts "SELECTED MACRO:#{selected}, #{m}"
21
+ id = $macro.last_macro
22
+ $macro.recorded_macros[id] = m
23
+ $macro.run_macro(id)
24
+ end
25
+
26
+ class Macro
27
+ # attr_reader :recorded_macros, :recording, :named_macros
28
+ attr_accessor :recorded_macros, :recording, :named_macros, :last_macro
29
+
30
+ def initialize()
31
+ @recording = false
32
+ # @recorded_macros = {}
33
+ @current_recording = []
34
+ @current_name = nil
35
+ @last_macro = "a"
36
+
37
+ #TODO:
38
+ @recorded_macros = vma.marshal_load("macros", {})
39
+ @named_macros = vma.marshal_load("named_macros", {})
40
+ $hook.register(:shutdown, self.method("save"))
41
+ end
42
+
43
+ def save()
44
+ vma.marshal_save("macros", @recorded_macros)
45
+ vma.marshal_save("named_macros", @named_macros)
46
+ end
47
+
48
+ def gui_name_macro()
49
+ callback = self.method("name_macro")
50
+ # gui_one_input_action("Grep", "Search:", "grep", "grep_cur_buffer")
51
+ gui_one_input_action("Name last macro", "Name:", "Set", callback)
52
+ end
53
+
54
+ def find_macro_gui()
55
+ # Ripl.start :binding => binding
56
+
57
+ l = $macro.named_macros.keys.sort.collect { |x| [x, 0] }
58
+ $macro_search_list = l
59
+ $select_keys = ["h", "l", "f", "d", "s", "a", "g", "z"]
60
+
61
+ qt_select_update_window(l, $select_keys.collect { |x| x.upcase },
62
+ "gui_find_macro_select_callback",
63
+ "gui_find_macro_update_callback")
64
+ end
65
+
66
+ def name_macro(name, id = nil)
67
+ puts "NAME MACRO #{name}"
68
+ if id.nil?
69
+ id = @last_macro
70
+ end
71
+ @named_macros[name] = @recorded_macros[id].clone
72
+ end
73
+
74
+ def start_recording(name)
75
+ @recording = true
76
+ @current_name = name
77
+ @current_recording = []
78
+ message("Start recording macro [#{name}]")
79
+
80
+ # Returning false prevents from putting start_recording to start of macro
81
+ return false
82
+ end
83
+
84
+ def end_recording()
85
+ if @recording == true
86
+ @recorded_macros[@current_name] = @current_recording
87
+ @last_macro = @current_name
88
+ @current_name = @current_recording = nil
89
+ @recording = false
90
+ message("Stop recording macro [#{@last_macro}]")
91
+ else
92
+ message("Not recording macro")
93
+ end
94
+ end
95
+
96
+ def is_recording
97
+ return @recording
98
+ end
99
+
100
+ def record_action(eval_str)
101
+ if @recording
102
+ if eval_str == "repeat_last_action"
103
+ @current_recording << $command_history.last
104
+ else
105
+ @current_recording << eval_str
106
+ end
107
+ end
108
+ end
109
+
110
+ # Allow method to specify the macro action instead of recording from keyboard input
111
+ def overwrite_current_action(eval_str)
112
+ if @recording
113
+ @current_recording[-1] = eval_str
114
+ end
115
+ end
116
+
117
+ def run_last_macro
118
+ run_macro(@last_macro)
119
+ end
120
+
121
+ def run_macro(name)
122
+ if $macro.is_recording == true
123
+ message("Can't run a macro that runs a macro (recursion risk)")
124
+ return false
125
+ end
126
+ message("Start running macro [#{name}]")
127
+ if @recorded_macros.has_key?(name)
128
+ @last_macro = name
129
+ end
130
+ acts = @recorded_macros[name]
131
+ if acts.kind_of?(Array) and acts.any?
132
+ set_last_command({ method: $macro.method("run_macro"), params: [name] })
133
+ #
134
+ # Ripl.start :binding => binding
135
+ for a in acts
136
+ ret = exec_action(a)
137
+ puts ret
138
+ if ret == false
139
+ message("Error while running macro")
140
+ break
141
+ end
142
+ end
143
+ # eval_str = m.join(";")
144
+ # debug(eval_str)
145
+ # eval(eval_str)
146
+ end
147
+ buf.set_pos(buf.pos)
148
+ end
149
+
150
+ def save_macro(name)
151
+ m = @recorded_macros[name]
152
+ return if !(m.kind_of?(Array) and m.any?)
153
+ contents = m.join(";")
154
+ dot_dir = File.expand_path("~/.vimamsa")
155
+ Dir.mkdir(dot_dir) unless File.exist?(dot_dir)
156
+ save_fn = "#{dot_dir}/macro_#{name}.rb"
157
+
158
+ Thread.new {
159
+ File.open(save_fn, "w+") do |io|
160
+ #io.set_encoding(self.encoding)
161
+
162
+ begin
163
+ io.write(contents)
164
+ rescue Encoding::UndefinedConversionError => ex
165
+ # this might happen when trying to save UTF-8 as US-ASCII
166
+ # so just warn, try to save as UTF-8 instead.
167
+ warn("Saving as UTF-8 because of: #{ex.class}: #{ex}")
168
+ io.rewind
169
+
170
+ io.set_encoding(Encoding::UTF_8)
171
+ io.write(contents)
172
+ end
173
+ end
174
+ sleep 3 #TODO:remove
175
+ }
176
+ end
177
+ end
@@ -0,0 +1,71 @@
1
+ #scriptdir=File.expand_path(File.dirname(__FILE__))
2
+ $:.unshift File.dirname(__FILE__) + "/lib"
3
+
4
+ # require 'benchmark/ips'
5
+
6
+ # load "vendor/ver/lib/ver/vendor/textpow.rb"
7
+ # load "vendor/ver/lib/ver/syntax/detector.rb"
8
+ # load "vendor/ver/config/detect.rb"
9
+
10
+ require "differ"
11
+ module Differ
12
+ class Diff
13
+ def get_raw_array()
14
+ return @raw
15
+ end
16
+ end
17
+ end
18
+
19
+ Encoding.default_external = Encoding::UTF_8
20
+ Encoding.default_internal = Encoding::UTF_8
21
+
22
+ # Globals
23
+ $command_history = []
24
+ $clipboard = []
25
+ $register = Hash.new("")
26
+ $cnf = {}
27
+ $search_dirs = []
28
+ $errors = []
29
+
30
+ $cur_register = "a"
31
+ $input_char_call_func = nil
32
+ $debuginfo = {}
33
+
34
+ $jump_sequence = []
35
+
36
+ $debug = false
37
+ $experimental = false
38
+
39
+ # Return currently active buffer
40
+ def buf()
41
+ return $buffer
42
+ end
43
+
44
+ def bufs()
45
+ return $buffers
46
+ end
47
+
48
+ def buflist()
49
+ return $buffers
50
+ end
51
+
52
+ require "vimamsa/editor.rb"
53
+
54
+ # load "qt_funcs.rb"
55
+
56
+ $vma = Editor.new
57
+ def vma()
58
+ return $vma
59
+ end
60
+
61
+ # c_startup
62
+ # run_random_jump_test
63
+ # main_loop
64
+
65
+ # debug("END")
66
+
67
+
68
+
69
+
70
+
71
+
@@ -0,0 +1,1014 @@
1
+ require "rbvma/version"
2
+ require "gtk3"
3
+ require "gtksourceview3"
4
+ #require "gtksourceview4"
5
+ require "ripl"
6
+ require "fileutils"
7
+ require "pathname"
8
+ require "date"
9
+ require "ripl/multi_line"
10
+ require "json"
11
+
12
+ puts "INIT rbvma"
13
+
14
+ require "vimamsa/util"
15
+ # require "rbvma/rbvma"
16
+ require "vimamsa/main" #
17
+ require "vimamsa/key_binding_tree" #
18
+ require "vimamsa/actions" #
19
+ require "vimamsa/macro" #
20
+ require "vimamsa/buffer" #
21
+ require "vimamsa/debug" #
22
+ require "vimamsa/constants"
23
+ require "vimamsa/easy_jump"
24
+ require "vimamsa/hook"
25
+ require "vimamsa/search"
26
+ require "vimamsa/search_replace"
27
+ require "vimamsa/buffer_list"
28
+ require "vimamsa/file_finder"
29
+ require "vimamsa/hyper_plain_text"
30
+ require "vimamsa/ack"
31
+ require "vimamsa/encrypt"
32
+ require "vimamsa/file_manager"
33
+
34
+ # load "vendor/ver/lib/ver/vendor/textpow.rb"
35
+ # load "vendor/ver/lib/ver/syntax/detector.rb"
36
+ # load "vendor/ver/config/detect.rb"
37
+
38
+ $vma = Editor.new
39
+
40
+ def vma()
41
+ return $vma
42
+ end
43
+
44
+ $idle_scroll_to_mark = false
45
+
46
+ def idle_func
47
+ # puts "IDLEFUNC"
48
+ if $idle_scroll_to_mark
49
+ # Ripl.start :binding => binding
50
+ # $view.get_visible_rect
51
+ vr = $view.visible_rect
52
+
53
+ # iter = b.get_iter_at(:offset => i)
54
+
55
+ b = $view.buffer
56
+ iter = b.get_iter_at(:offset => b.cursor_position)
57
+ iterxy = $view.get_iter_location(iter)
58
+ # puts "ITERXY" + iterxy.inspect
59
+ # Ripl.start :binding => binding
60
+
61
+ intr = iterxy.intersect(vr)
62
+ if intr.nil?
63
+ $view.set_cursor_pos($view.buffer.cursor_position)
64
+ else
65
+ $idle_scroll_to_mark = false
66
+ end
67
+
68
+ sleep(0.1)
69
+ end
70
+ sleep(0.01)
71
+ return true
72
+ end
73
+
74
+ # qt_select_update_window(l, $select_keys.collect { |x| x.upcase },
75
+ # "gui_find_macro_select_callback",
76
+ # "gui_find_macro_update_callback")
77
+ class SelectUpdateWindow
78
+ COLUMN_JUMP_KEY = 0
79
+ COLUMN_DESCRIPTION = 1
80
+
81
+ def update_item_list(item_list)
82
+ # puts item_list.inspect
83
+ # Ripl.start :binding => binding
84
+ @model.clear
85
+ for item in item_list
86
+ iter = @model.append
87
+ v = ["", item[0]]
88
+ puts v.inspect
89
+ iter.set_values(v)
90
+ end
91
+
92
+ set_selected_row(0)
93
+ end
94
+
95
+ def set_selected_row(rownum)
96
+ rownum = 0 if rownum < 0
97
+ @selected_row = rownum
98
+
99
+ if @model.count > 0
100
+ path = Gtk::TreePath.new(@selected_row.to_s)
101
+ iter = @model.get_iter(path)
102
+ @tv.selection.select_iter(iter)
103
+ end
104
+ end
105
+
106
+ def initialize(main_window, item_list, jump_keys, select_callback, update_callback)
107
+ @window = Gtk::Window.new(:toplevel)
108
+ # @window.screen = main_window.screen
109
+ @window.title = "List Store"
110
+
111
+ @selected_row = 0
112
+
113
+ puts item_list.inspect
114
+ @update_callback = method(update_callback)
115
+ @select_callback = method(select_callback)
116
+ # puts @update_callback_m.call("").inspect
117
+
118
+ vbox = Gtk::Box.new(:vertical, 8)
119
+ vbox.margin = 8
120
+ @window.add(vbox)
121
+
122
+ @entry = Gtk::SearchEntry.new
123
+ @entry.width_chars = 45
124
+ container = Gtk::Box.new(:horizontal, 10)
125
+ # container.halign = :start
126
+ container.halign = :center
127
+ container.pack_start(@entry,
128
+ :expand => false, :fill => false, :padding => 0)
129
+
130
+ # create tree view
131
+ @model = Gtk::ListStore.new(String, String)
132
+ treeview = Gtk::TreeView.new(@model)
133
+ treeview.search_column = COLUMN_DESCRIPTION
134
+ @tv = treeview
135
+ # item_list = @update_callback.call("")
136
+ update_item_list(item_list)
137
+
138
+ # Ripl.start :binding => binding
139
+ @window.signal_connect("key-press-event") do |_widget, event|
140
+ # puts "KEYPRESS 1"
141
+ @entry.handle_event(event)
142
+ end
143
+
144
+ @entry.signal_connect("key_press_event") do |widget, event|
145
+ # puts "KEYPRESS 2"
146
+ if event.keyval == Gdk::Keyval::KEY_Down
147
+ puts "DOWN"
148
+ set_selected_row(@selected_row + 1)
149
+ # fixed = iter[COLUMN_FIXED]
150
+
151
+ true
152
+ elsif event.keyval == Gdk::Keyval::KEY_Up
153
+ set_selected_row(@selected_row - 1)
154
+ puts "UP"
155
+ true
156
+ elsif event.keyval == Gdk::Keyval::KEY_Return
157
+ path = Gtk::TreePath.new(@selected_row.to_s)
158
+ iter = @model.get_iter(path)
159
+ ret = iter[1]
160
+ @select_callback.call(ret, @selected_row)
161
+ @window.destroy
162
+ # puts iter[1].inspect
163
+ true
164
+ elsif event.keyval == Gdk::Keyval::KEY_Escape
165
+ @window.destroy
166
+ true
167
+ else
168
+ false
169
+ end
170
+ end
171
+
172
+ @entry.signal_connect("search-changed") do |widget|
173
+ puts "search changed: #{widget.text || ""}"
174
+ item_list = @update_callback.call(widget.text)
175
+ update_item_list(item_list)
176
+ # label.text = widget.text || ""
177
+ end
178
+ @entry.signal_connect("changed") { puts "[changed] " }
179
+ @entry.signal_connect("next-match") { puts "[next-match] " }
180
+
181
+ label = Gtk::Label.new(<<-EOF)
182
+
183
+ Search:
184
+ EOF
185
+ vbox.pack_start(label, :expand => false, :fill => false, :padding => 0)
186
+
187
+ vbox.pack_start(container, :expand => false, :fill => false, :padding => 0)
188
+ sw = Gtk::ScrolledWindow.new(nil, nil)
189
+ sw.shadow_type = :etched_in
190
+ sw.set_policy(:never, :automatic)
191
+ vbox.pack_start(sw, :expand => true, :fill => true, :padding => 0)
192
+
193
+ sw.add(treeview)
194
+
195
+ renderer = Gtk::CellRendererText.new
196
+ column = Gtk::TreeViewColumn.new("JMP",
197
+ renderer,
198
+ "text" => COLUMN_JUMP_KEY)
199
+ column.sort_column_id = COLUMN_JUMP_KEY
200
+ treeview.append_column(column)
201
+
202
+ renderer = Gtk::CellRendererText.new
203
+ column = Gtk::TreeViewColumn.new("Description",
204
+ renderer,
205
+ "text" => COLUMN_DESCRIPTION)
206
+ column.sort_column_id = COLUMN_DESCRIPTION
207
+ treeview.append_column(column)
208
+
209
+ @window.set_default_size(280, 500)
210
+ puts "SelectUpdateWindow"
211
+ end
212
+
213
+ def run
214
+ if !@window.visible?
215
+ @window.show_all
216
+ # add_spinner
217
+ else
218
+ @window.destroy
219
+ # GLib::Source.remove(@tiemout) unless @timeout.zero?
220
+ @timeout = 0
221
+ end
222
+ @window
223
+ end
224
+ end
225
+
226
+ def center_on_current_line()
227
+ b = $view.buffer
228
+ iter = b.get_iter_at(:offset => b.cursor_position)
229
+ within_margin = 0.0 #margin as a [0.0,0.5) fraction of screen size
230
+ use_align = true
231
+ xalign = 0.0 #0.0=top 1.0=bottom, 0.5=center
232
+ yalign = 0.5
233
+ $view.scroll_to_iter(iter, within_margin, use_align, xalign, yalign)
234
+ end
235
+
236
+ def qt_select_update_window(item_list, jump_keys, select_callback, update_callback)
237
+ $selup = SelectUpdateWindow.new(nil, item_list, jump_keys, select_callback, update_callback)
238
+ $selup.run
239
+ end
240
+
241
+ # ~/Drive/code/ruby-gnome/gtk3/sample/gtk-demo/search_entry2.rb
242
+ # ~/Drive/code/ruby-gnome/gtk3/sample/gtk-demo/list_store.rb
243
+
244
+ def qt_open_file_dialog(dirpath)
245
+ dialog = Gtk::FileChooserDialog.new(:title => "Open file",
246
+ :action => :open,
247
+ :buttons => [[Gtk::Stock::OPEN, :accept],
248
+ [Gtk::Stock::CANCEL, :cancel]])
249
+ dialog.set_current_folder(dirpath)
250
+
251
+ dialog.signal_connect("response") do |dialog, response_id|
252
+ if response_id == Gtk::ResponseType::ACCEPT
253
+ open_new_file(dialog.filename)
254
+ # puts "uri = #{dialog.uri}"
255
+ end
256
+ dialog.destroy
257
+ end
258
+ dialog.run
259
+ end
260
+
261
+ def qt_file_saveas(dirpath)
262
+ dialog = Gtk::FileChooserDialog.new(:title => "Save as",
263
+ :action => :save,
264
+ :buttons => [[Gtk::Stock::SAVE, :accept],
265
+ [Gtk::Stock::CANCEL, :cancel]])
266
+ dialog.set_current_folder(dirpath)
267
+ dialog.signal_connect("response") do |dialog, response_id|
268
+ if response_id == Gtk::ResponseType::ACCEPT
269
+ file_saveas(dialog.filename)
270
+ end
271
+ dialog.destroy
272
+ end
273
+
274
+ dialog.run
275
+ end
276
+
277
+ def qt_create_buffer(id)
278
+ puts "qt_create_buffer(#{id})"
279
+ buf1 = GtkSource::Buffer.new()
280
+ view = VSourceView.new()
281
+
282
+ view.set_highlight_current_line(true)
283
+ view.set_show_line_numbers(true)
284
+ view.set_buffer(buf1)
285
+
286
+ ssm = GtkSource::StyleSchemeManager.new
287
+ ssm.set_search_path(ssm.search_path << ppath("styles/"))
288
+ # sty = ssm.get_scheme("dark")
289
+ sty = ssm.get_scheme("molokai_edit")
290
+ # puts ssm.scheme_ids
291
+
292
+ view.buffer.highlight_matching_brackets = true
293
+ view.buffer.style_scheme = sty
294
+
295
+ provider = Gtk::CssProvider.new
296
+ provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
297
+ # provider.load(data: "textview { font-family: Arial; font-size: 12pt; }")
298
+ view.style_context.add_provider(provider)
299
+ view.wrap_mode = :char
300
+
301
+ $vmag.buffers[id] = view
302
+ end
303
+
304
+ def gui_set_file_lang(id, lname)
305
+ view = $vmag.buffers[id]
306
+ lm = GtkSource::LanguageManager.new
307
+ lang = nil
308
+ lm.set_search_path(lm.search_path << ppath("lang/"))
309
+ lang = lm.get_language(lname)
310
+
311
+ view.buffer.language = lang
312
+ view.buffer.highlight_syntax = true
313
+ end
314
+
315
+ def qt_process_deltas
316
+ end
317
+
318
+ def qt_add_image(imgpath, pos)
319
+ end
320
+
321
+ def qt_process_deltas
322
+ end
323
+
324
+ def qt_process_events
325
+ end
326
+
327
+ def qt_select_window_close(arg = nil)
328
+ end
329
+
330
+ def set_window_title(str)
331
+ unimplemented
332
+ end
333
+
334
+ def render_text(tmpbuf, pos, selection_start, reset)
335
+ unimplemented
336
+ end
337
+
338
+ def qt_set_buffer_contents(id, txt)
339
+ # $vbuf.set_text(txt)
340
+ puts "qt_set_buffer_contents(#{id}, txt)"
341
+
342
+ $vmag.buffers[id].buffer.set_text(txt)
343
+ end
344
+
345
+ def qt_set_cursor_pos(id, pos)
346
+ $view.set_cursor_pos(pos)
347
+ # Ripl.start :binding => binding
348
+ end
349
+
350
+ def qt_set_selection_start(id, selection_start)
351
+ end
352
+
353
+ def qt_set_current_buffer(id)
354
+ view = $vmag.buffers[id]
355
+ puts "qt_set_current_buffer(#{id}), view=#{view}"
356
+ buf1 = view.buffer
357
+ $vmag.view = view
358
+ $vmag.buf1 = buf1
359
+ $view = view
360
+ $vbuf = buf1
361
+
362
+ $vmag.sw.remove($vmag.sw.child) if !$vmag.sw.child.nil?
363
+ $vmag.sw.add(view)
364
+
365
+ view.grab_focus
366
+ #view.set_focus(10)
367
+ view.set_cursor_visible(true)
368
+ #view.move_cursor(1, 1, false)
369
+ view.place_cursor_onscreen
370
+
371
+ #TODO:
372
+ # itr = view.buffer.get_iter_at(:offset => 0)
373
+ # view.buffer.place_cursor(itr)
374
+
375
+ wtitle = ""
376
+ wtitle = buf.fname if !buf.fname.nil?
377
+ $vmag.window.title = wtitle
378
+ $vmag.sw.show_all
379
+ end
380
+
381
+ def unimplemented
382
+ puts "unimplemented"
383
+ end
384
+
385
+ def center_where_cursor
386
+ unimplemented
387
+ end
388
+
389
+ def paste_system_clipboard()
390
+ # clipboard = $vmag.window.get_clipboard(Gdk::Selection::CLIPBOARD)
391
+ utf8_string = Gdk::Atom.intern("UTF8_STRING")
392
+ # x = clipboard.request_contents(utf8_string)
393
+
394
+ widget = Gtk::Invisible.new
395
+ clipboard = Gtk::Clipboard.get_default($vmag.window.display)
396
+ received_text = ""
397
+
398
+ target_string = Gdk::Selection::TARGET_STRING
399
+ ti = clipboard.request_contents(target_string)
400
+
401
+ # clipboard.request_contents(target_string) do |_clipboard, selection_data|
402
+ # received_text = selection_data.text
403
+ # puts "received_text=#{received_text}"
404
+ # end
405
+ if clipboard.wait_is_text_available?
406
+ received_text = clipboard.wait_for_text
407
+ end
408
+
409
+ if received_text != "" and !received_text.nil?
410
+ max_clipboard_items = 100
411
+ if received_text != $clipboard[-1]
412
+ #TODO: HACK
413
+ $paste_lines = false
414
+ end
415
+ $clipboard << received_text
416
+ # puts $clipboard[-1]
417
+ $clipboard = $clipboard[-([$clipboard.size, max_clipboard_items].min)..-1]
418
+ end
419
+ return received_text
420
+ end
421
+
422
+ def set_system_clipboard(arg)
423
+ # return if arg.class != String
424
+ # return if s.size < 1
425
+ # utf8_string = Gdk::Atom.intern("UTF8_STRING")
426
+ widget = Gtk::Invisible.new
427
+ clipboard = Gtk::Clipboard.get_default($vmag.window.display)
428
+ clipboard.text = arg
429
+ end
430
+
431
+ def get_visible_area()
432
+ view = $view
433
+ vr = view.visible_rect
434
+ startpos = view.get_iter_at_position_raw(vr.x, vr.y)[1].offset
435
+ endpos = view.get_iter_at_position_raw(vr.x + vr.width, vr.y + vr.height)[1].offset
436
+ return [startpos, endpos]
437
+ end
438
+
439
+ def page_up
440
+ $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
441
+ return true
442
+ end
443
+
444
+ def page_down
445
+ $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), 1, false)
446
+ return true
447
+ end
448
+
449
+ # module Rbvma
450
+ # # Your code goes here...
451
+ # def foo
452
+ # puts "BAR"
453
+ # end
454
+ # end
455
+ $debug = true
456
+
457
+ def scan_indexes(txt, regex)
458
+ # indexes = txt.enum_for(:scan, regex).map { Regexp.last_match.begin(0) + 1 }
459
+ indexes = txt.enum_for(:scan, regex).map { Regexp.last_match.begin(0) }
460
+ return indexes
461
+ end
462
+
463
+ $update_cursor = false
464
+
465
+ class VSourceView < GtkSource::View
466
+ def initialize(title = nil)
467
+ # super(:toplevel)
468
+ super()
469
+ puts "vsource init"
470
+ @last_keyval = nil
471
+ @last_event = [nil, nil]
472
+
473
+ signal_connect("key_press_event") do |widget, event|
474
+ handle_key_event(event, :key_press_event)
475
+ true
476
+ end
477
+
478
+ signal_connect("key_release_event") do |widget, event|
479
+ handle_key_event(event, :key_release_event)
480
+ true
481
+ end
482
+
483
+ signal_connect("move-cursor") do |widget, event|
484
+ $update_cursor = true
485
+ false
486
+ end
487
+
488
+ signal_connect "button-release-event" do |widget, event|
489
+ $buffer.set_pos(buffer.cursor_position)
490
+ false
491
+ end
492
+ @curpos_mark = nil
493
+ end
494
+
495
+ def handle_key_event(event, sig)
496
+ if $update_cursor
497
+ curpos = buffer.cursor_position
498
+ puts "MOVE CURSOR: #{curpos}"
499
+ buf.set_pos(curpos)
500
+ $update_cursor = false
501
+ end
502
+ puts $view.visible_rect.inspect
503
+
504
+ puts "key event"
505
+ puts event
506
+
507
+ key_name = event.string
508
+ if event.state.control_mask?
509
+ key_name = Gdk::Keyval.to_name(event.keyval)
510
+ # Gdk::Keyval.to_name()
511
+ end
512
+
513
+ keyval_trans = {}
514
+ keyval_trans[Gdk::Keyval::KEY_Control_L] = "ctrl"
515
+ keyval_trans[Gdk::Keyval::KEY_Control_R] = "ctrl"
516
+
517
+ keyval_trans[Gdk::Keyval::KEY_Escape] = "esc"
518
+
519
+ keyval_trans[Gdk::Keyval::KEY_Return] = "enter"
520
+ keyval_trans[Gdk::Keyval::KEY_ISO_Enter] = "enter"
521
+ keyval_trans[Gdk::Keyval::KEY_KP_Enter] = "enter"
522
+ keyval_trans[Gdk::Keyval::KEY_Alt_L] = "alt"
523
+ keyval_trans[Gdk::Keyval::KEY_Alt_R] = "alt"
524
+
525
+ keyval_trans[Gdk::Keyval::KEY_BackSpace] = "backspace"
526
+ keyval_trans[Gdk::Keyval::KEY_KP_Page_Down] = "pagedown"
527
+ keyval_trans[Gdk::Keyval::KEY_KP_Page_Up] = "pageup"
528
+ keyval_trans[Gdk::Keyval::KEY_Page_Down] = "pagedown"
529
+ keyval_trans[Gdk::Keyval::KEY_Page_Up] = "pageup"
530
+ keyval_trans[Gdk::Keyval::KEY_Left] = "left"
531
+ keyval_trans[Gdk::Keyval::KEY_Right] = "right"
532
+ keyval_trans[Gdk::Keyval::KEY_Down] = "down"
533
+ keyval_trans[Gdk::Keyval::KEY_Up] = "up"
534
+ keyval_trans[Gdk::Keyval::KEY_space] = "space"
535
+
536
+ keyval_trans[Gdk::Keyval::KEY_Shift_L] = "shift"
537
+ keyval_trans[Gdk::Keyval::KEY_Shift_R] = "shift"
538
+ keyval_trans[Gdk::Keyval::KEY_Tab] = "tab"
539
+
540
+ key_trans = {}
541
+ key_trans["\e"] = "esc"
542
+ tk = keyval_trans[event.keyval]
543
+ key_name = tk if !tk.nil?
544
+
545
+ key_str_parts = []
546
+ key_str_parts << "ctrl" if event.state.control_mask? and key_name != "ctrl"
547
+ key_str_parts << "alt" if event.state.mod1_mask? and key_name != "alt"
548
+
549
+ key_str_parts << key_name
550
+ key_str = key_str_parts.join("-")
551
+ keynfo = { :key_str => key_str, :key_name => key_name, :keyval => event.keyval }
552
+ puts keynfo.inspect
553
+ # $kbd.match_key_conf(key_str, nil, :key_press)
554
+ # puts "key_str=#{key_str} key_"
555
+
556
+ if key_str != "" # or prefixed_key_str != ""
557
+ if sig == :key_release_event and event.keyval == @last_keyval
558
+ $kbd.match_key_conf(key_str + "!", nil, :key_release)
559
+ @last_event = [event, :key_release]
560
+ elsif sig == :key_press_event
561
+ $kbd.match_key_conf(key_str, nil, :key_press)
562
+ @last_event = [event, key_str, :key_press]
563
+ end
564
+ @last_keyval = event.keyval #TODO: outside if?
565
+ end
566
+
567
+ handle_deltas
568
+
569
+ # set_focus(5)
570
+ # false
571
+
572
+ end
573
+
574
+ def pos_to_coord(i)
575
+ b = buffer
576
+ iter = b.get_iter_at(:offset => i)
577
+ iterxy = get_iter_location(iter)
578
+ winw = parent_window.width
579
+ view_width = visible_rect.width
580
+ gutter_width = winw - view_width
581
+
582
+ x = iterxy.x + gutter_width
583
+ y = iterxy.y
584
+
585
+ # buffer_to_window_coords(Gtk::TextWindowType::TEXT, iterxy.x, iterxy.y).inspect
586
+ # puts buffer_to_window_coords(Gtk::TextWindowType::TEXT, x, y).inspect
587
+ (x, y) = buffer_to_window_coords(Gtk::TextWindowType::TEXT, x, y)
588
+ # Ripl.start :binding => binding
589
+
590
+ return [x, y]
591
+ end
592
+
593
+ def handle_deltas()
594
+ any_change = false
595
+ while d = buf.deltas.shift
596
+ any_change = true
597
+ pos = d[0]
598
+ op = d[1]
599
+ num = d[2]
600
+ txt = d[3]
601
+ if op == DELETE
602
+ startiter = buffer.get_iter_at(:offset => pos)
603
+ enditer = buffer.get_iter_at(:offset => pos + num)
604
+ buffer.delete(startiter, enditer)
605
+ elsif op == INSERT
606
+ startiter = buffer.get_iter_at(:offset => pos)
607
+ buffer.insert(startiter, txt)
608
+ end
609
+ end
610
+ if any_change
611
+ qt_set_cursor_pos($buffer.id, $buffer.pos) #TODO: only when necessary
612
+ end
613
+
614
+ # sanity_check #TODO
615
+ end
616
+
617
+ def sanity_check()
618
+ a = buffer.text
619
+ b = buf.to_s
620
+ # puts "===================="
621
+ # puts a.lines[0..10].join()
622
+ # puts "===================="
623
+ # puts b.lines[0..10].join()
624
+ # puts "===================="
625
+ if a == b
626
+ puts "Buffers match"
627
+ else
628
+ puts "ERROR: Buffer's don't match."
629
+ end
630
+ end
631
+
632
+ def set_cursor_pos(pos)
633
+ # return
634
+ itr = buffer.get_iter_at(:offset => pos)
635
+ itr2 = buffer.get_iter_at(:offset => pos + 1)
636
+ buffer.place_cursor(itr)
637
+
638
+ # $view.signal_emit("extend-selection", Gtk::MovementStep.new(:PAGES), -1, false)
639
+
640
+ within_margin = 0.075 #margin as a [0.0,0.5) fraction of screen size
641
+ use_align = false
642
+ xalign = 0.5 #0.0=top 1.0=bottom, 0.5=center
643
+ yalign = 0.5
644
+
645
+ if @curpos_mark.nil?
646
+ @curpos_mark = buffer.create_mark("cursor", itr, false)
647
+ else
648
+ buffer.move_mark(@curpos_mark, itr)
649
+ end
650
+ scroll_to_mark(@curpos_mark, within_margin, use_align, xalign, yalign)
651
+ $idle_scroll_to_mark = true
652
+ ensure_cursor_visible
653
+
654
+ # scroll_to_iter(itr, within_margin, use_align, xalign, yalign)
655
+
656
+ # $view.signal_emit("extend-selection", Gtk::TextExtendSelection.new, itr,itr,itr2)
657
+ # Ripl.start :binding => binding
658
+ draw_cursor
659
+
660
+ return true
661
+ end
662
+
663
+ def cursor_visible_idle_func
664
+ puts "cursor_visible_idle_func"
665
+ # From https://picheta.me/articles/2013/08/gtk-plus--a-method-to-guarantee-scrolling.html
666
+ # vr = visible_rect
667
+
668
+ # b = $view.buffer
669
+ # iter = buffer.get_iter_at(:offset => buffer.cursor_position)
670
+ # iterxy = get_iter_location(iter)
671
+
672
+ sleep(0.01)
673
+ # intr = iterxy.intersect(vr)
674
+ if is_cursor_visible == false
675
+ # set_cursor_pos(buffer.cursor_position)
676
+
677
+ itr = buffer.get_iter_at(:offset => buffer.cursor_position)
678
+
679
+ within_margin = 0.075 #margin as a [0.0,0.5) fraction of screen size
680
+ use_align = false
681
+ xalign = 0.5 #0.0=top 1.0=bottom, 0.5=center
682
+ yalign = 0.5
683
+
684
+ scroll_to_iter(itr, within_margin, use_align, xalign, yalign)
685
+
686
+ # return true # Call this func again
687
+ else
688
+ return false # Don't call this idle func again
689
+ end
690
+ end
691
+
692
+ def is_cursor_visible
693
+ vr = visible_rect
694
+ iter = buffer.get_iter_at(:offset => buffer.cursor_position)
695
+ iterxy = get_iter_location(iter)
696
+ iterxy.width = 1 if iterxy.width == 0
697
+ iterxy.height = 1 if iterxy.height == 0
698
+
699
+ intr = iterxy.intersect(vr)
700
+ if intr.nil?
701
+ puts iterxy.inspect
702
+ puts vr.inspect
703
+ # Ripl.start :binding => binding
704
+
705
+ # exit!
706
+ return false
707
+ else
708
+ return true
709
+ end
710
+ end
711
+
712
+ def ensure_cursor_visible
713
+ if is_cursor_visible == false
714
+ Thread.new {
715
+ sleep 0.01
716
+ GLib::Idle.add(proc { cursor_visible_idle_func })
717
+ }
718
+ end
719
+ end
720
+
721
+ def draw_cursor
722
+ if is_command_mode
723
+ itr = buffer.get_iter_at(:offset => buf.pos)
724
+ itr2 = buffer.get_iter_at(:offset => buf.pos + 1)
725
+ $view.buffer.select_range(itr, itr2)
726
+ elsif buf.visual_mode?
727
+ puts "VISUAL MODE"
728
+ (_start, _end) = buf.get_visual_mode_range2
729
+ puts "#{_start}, #{_end}"
730
+ itr = buffer.get_iter_at(:offset => _start)
731
+ itr2 = buffer.get_iter_at(:offset => _end + 1)
732
+ $view.buffer.select_range(itr, itr2)
733
+ else # Insert mode
734
+ itr = buffer.get_iter_at(:offset => buf.pos)
735
+ $view.buffer.select_range(itr, itr)
736
+ puts "INSERT MODE"
737
+ end
738
+ end
739
+
740
+ # def quit
741
+ # destroy
742
+ # true
743
+ # end
744
+ end
745
+
746
+ class VMAg
747
+ attr_accessor :buffers, :sw, :view, :buf1, :window
748
+
749
+ VERSION = "1.0"
750
+
751
+ HEART = "♥"
752
+ RADIUS = 150
753
+ N_WORDS = 5
754
+ FONT = "Serif 18"
755
+ TEXT = "I ♥ GTK+"
756
+
757
+ def initialize()
758
+ @show_overlay = true
759
+ @da = nil
760
+ @buffers = {}
761
+ @view = nil
762
+ @buf1 = nil
763
+ end
764
+
765
+ def run
766
+ init_window
767
+ # init_rtext
768
+ Gtk.main
769
+ end
770
+
771
+ def start_overlay_draw()
772
+ @da = Gtk::Fixed.new
773
+ @overlay.add_overlay(@da)
774
+ @overlay.set_overlay_pass_through(@da, true)
775
+ end
776
+
777
+ def clear_overlay()
778
+ if @da != nil
779
+ @overlay.remove(@da)
780
+ end
781
+ end
782
+
783
+ def overlay_draw_text(text, textpos)
784
+ # puts "overlay_draw_text #{[x,y]}"
785
+ (x, y) = @view.pos_to_coord(textpos)
786
+ # puts "overlay_draw_text #{[x,y]}"
787
+ label = Gtk::Label.new("<span background='#00000088' foreground='#ff0000' weight='ultrabold'>#{text}</span>")
788
+ label.use_markup = true
789
+ @da.put(label, x, y)
790
+ end
791
+
792
+ def end_overlay_draw()
793
+ @da.show_all
794
+ end
795
+
796
+ def toggle_overlay
797
+ @show_overlay = @show_overlay ^ 1
798
+ if !@show_overlay
799
+ if @da != nil
800
+ @overlay.remove(@da)
801
+ end
802
+ return
803
+ else
804
+ @da = Gtk::Fixed.new
805
+ @overlay.add_overlay(@da)
806
+ @overlay.set_overlay_pass_through(@da, true)
807
+ end
808
+
809
+ (startpos, endpos) = get_visible_area
810
+ s = @view.buffer.text
811
+ wpos = s.enum_for(:scan, /\W(\w)/).map { Regexp.last_match.begin(0) + 1 }
812
+ wpos = wpos[0..130]
813
+
814
+ # vr = @view.visible_rect
815
+ # # gtk_text_view_get_line_at_y
816
+ # # gtk_text_view_get_iter_at_position
817
+ # gtk_text_view_get_iter_at_position(vr.
818
+ # istart = @view.get_iter_at_position(vr.x,vr.y)
819
+ # istart = @view.get_iter_at_y(vr.y)
820
+ # startpos = @view.get_iter_at_position_raw(vr.x,vr.y)[1].offset
821
+ # endpos = @view.get_iter_at_position_raw(vr.x+vr.width,vr.y+vr.height)[1].offset
822
+ # puts "startpos,endpos:#{[startpos, endpos]}"
823
+
824
+ da = @da
825
+ if false
826
+ da.signal_connect "draw" do |widget, cr|
827
+ cr.save
828
+ for pos in wpos
829
+ (x, y) = @view.pos_to_coord(pos)
830
+
831
+ layout = da.create_pango_layout("XY")
832
+ desc = Pango::FontDescription.new("sans bold 11")
833
+ layout.font_description = desc
834
+
835
+ cr.move_to(x, y)
836
+ # cr.move_to(gutter_width, 300)
837
+ cr.pango_layout_path(layout)
838
+
839
+ cr.set_source_rgb(1.0, 0.0, 0.0)
840
+ cr.fill_preserve
841
+ end
842
+ cr.restore
843
+ false # = draw other
844
+ # true # = Don't draw others
845
+ end
846
+ end
847
+
848
+ for pos in wpos
849
+ (x, y) = @view.pos_to_coord(pos)
850
+ # da.put(Gtk::Label.new("AB"), x, y)
851
+ label = Gtk::Label.new("<span background='#00000088' foreground='#ff0000' weight='ultrabold'>AB</span>")
852
+ label.use_markup = true
853
+ da.put(label, x, y)
854
+ end
855
+
856
+ # puts @view.pos_to_coord(300).inspect
857
+
858
+ @da.show_all
859
+ end
860
+
861
+ def init_keybindings
862
+ $kbd = KeyBindingTree.new()
863
+ $kbd.add_mode("C", :command)
864
+ $kbd.add_mode("I", :insert)
865
+ $kbd.add_mode("V", :visual)
866
+ $kbd.add_mode("M", :minibuffer)
867
+ $kbd.add_mode("R", :readchar)
868
+ $kbd.add_mode("B", :browse)
869
+ $kbd.set_default_mode(:command)
870
+ require "default_key_bindings"
871
+
872
+ $macro = Macro.new
873
+
874
+ # bindkey "VC j", "buf.move(FORWARD_LINE)"
875
+ bindkey "VC j", "puts('j_key_action')"
876
+ bindkey "VC ctrl-j", "puts('ctrl_j_key_action')"
877
+
878
+ bindkey "VC l", "buf.move(FORWARD_CHAR)"
879
+ bindkey "C x", "buf.delete(CURRENT_CHAR_FORWARD)"
880
+ # bindkey "C r <char>", "buf.replace_with_char(<char>)"
881
+ bindkey "I space", 'buf.insert_txt(" ")'
882
+
883
+ bindkey "VC l", "buf.move(FORWARD_CHAR)"
884
+ bindkey "VC j", "buf.move(FORWARD_LINE)"
885
+ bindkey "VC k", "buf.move(BACKWARD_LINE)"
886
+ bindkey "VC h", "buf.move(BACKWARD_CHAR)"
887
+ end
888
+
889
+ def handle_deltas()
890
+ while d = buf.deltas.shift
891
+ pos = d[0]
892
+ op = d[1]
893
+ num = d[2]
894
+ txt = d[3]
895
+ if op == DELETE
896
+ startiter = @buf1.get_iter_at(:offset => pos)
897
+ enditer = @buf1.get_iter_at(:offset => pos + num)
898
+ @buf1.delete(startiter, enditer)
899
+ elsif op == INSERT
900
+ startiter = @buf1.get_iter_at(:offset => pos)
901
+ @buf1.insert(startiter, txt)
902
+ end
903
+ end
904
+ end
905
+
906
+ def add_to_minibuf(msg)
907
+ startiter = @minibuf.buffer.get_iter_at(:offset => 0)
908
+ @minibuf.buffer.insert(startiter, "#{msg}\n")
909
+ @minibuf.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
910
+ end
911
+
912
+ def init_minibuffer()
913
+ # Init minibuffer
914
+ sw = Gtk::ScrolledWindow.new
915
+ sw.set_policy(:automatic, :automatic)
916
+ overlay = Gtk::Overlay.new
917
+ overlay.add(sw)
918
+ @vpaned.pack2(overlay, :resize => false)
919
+ # overlay.set_size_request(-1, 50)
920
+ # $ovrl = overlay
921
+ # $ovrl.set_size_request(-1, 30)
922
+ $sw2 = sw
923
+ sw.set_size_request(-1, 12)
924
+
925
+ view = VSourceView.new()
926
+ view.set_highlight_current_line(false)
927
+ view.set_show_line_numbers(false)
928
+ # view.set_buffer(buf1)
929
+ ssm = GtkSource::StyleSchemeManager.new
930
+ ssm.set_search_path(ssm.search_path << ppath("styles/"))
931
+ sty = ssm.get_scheme("molokai_edit")
932
+ view.buffer.highlight_matching_brackets = false
933
+ view.buffer.style_scheme = sty
934
+ provider = Gtk::CssProvider.new
935
+ # provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
936
+ provider.load(data: "textview { font-family: Arial; font-size: 10pt; color:#ff0000}")
937
+ view.style_context.add_provider(provider)
938
+ view.wrap_mode = :char
939
+ @minibuf = view
940
+ # Ripl.start :binding => binding
941
+ # startiter = view.buffer.get_iter_at(:offset => 0)
942
+ message("STARTUP")
943
+ sw.add(view)
944
+ end
945
+
946
+ def init_header_bar()
947
+ # @window = Gtk::Window.new(:toplevel)
948
+ # @window.screen = main_window.screen
949
+ # @window.set_default_size(600, 400)
950
+
951
+ header = Gtk::HeaderBar.new
952
+ header.show_close_button = true
953
+ header.title = "Welcome to Facebook - Log in, sign up or learn more"
954
+ header.has_subtitle = false
955
+
956
+ # icon = Gio::ThemedIcon.new("mail-send-receive-symbolic")
957
+ # icon = Gio::ThemedIcon.new("document-open-symbolic")
958
+ # icon = Gio::ThemedIcon.new("dialog-password")
959
+
960
+ #edit-redo edit-paste edit-find-replace edit-undo edit-find edit-cut edit-copy
961
+ #document-open document-save document-save-as document-properties document-new
962
+ button = Gtk::Button.new
963
+ icon = Gio::ThemedIcon.new("open-menu-symbolic")
964
+ image = Gtk::Image.new(:icon => icon, :size => :button)
965
+ button.add(image)
966
+ header.pack_end(button)
967
+
968
+ button = Gtk::Button.new
969
+ icon = Gio::ThemedIcon.new("document-revert-symbolic")
970
+ image = Gtk::Image.new(:icon => icon, :size => :button)
971
+ button.add(image)
972
+ header.pack_end(button)
973
+
974
+ box = Gtk::Box.new(:horizontal, 0)
975
+ box.style_context.add_class("linked")
976
+
977
+ button = Gtk::Button.new
978
+ image = Gtk::Image.new(:icon_name => "pan-start-symbolic", :size => :button)
979
+ button.add(image)
980
+ box.add(button)
981
+
982
+ button = Gtk::Button.new
983
+ image = Gtk::Image.new(:icon_name => "pan-end-symbolic", :size => :button)
984
+ button.add(image)
985
+ box.add(button)
986
+
987
+ header.pack_start(box)
988
+ @window.titlebar = header
989
+ @window.add(Gtk::TextView.new)
990
+ end
991
+
992
+ def init_window
993
+ @window = Gtk::Window.new(:toplevel)
994
+ @window.set_default_size(650, 850)
995
+ @window.title = "Multiple Views"
996
+ @window.show_all
997
+ # vpaned = Gtk::Paned.new(:horizontal)
998
+ @vpaned = Gtk::Paned.new(:vertical)
999
+ @window.add(@vpaned)
1000
+
1001
+ @sw = Gtk::ScrolledWindow.new
1002
+ @sw.set_policy(:automatic, :automatic)
1003
+ @overlay = Gtk::Overlay.new
1004
+ @overlay.add(@sw)
1005
+ @vpaned.pack1(@overlay, :resize => true)
1006
+
1007
+ init_minibuffer
1008
+ init_header_bar
1009
+
1010
+ @window.show_all
1011
+
1012
+ vma.start
1013
+ end
1014
+ end