vimamsa 0.1.17 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e861051f02f35b286c8e97c225b69b9377f1d5cdf3dcf311de89a2ababb9dcd9
4
- data.tar.gz: c27f3bc13a925dbd0293592f9d692a1918e91a7ce8047868c340098be76d1613
3
+ metadata.gz: d29e057a168e6c2152c0d8da4c6957b863bd44e7dd9328ba2d5520ae11ab49a2
4
+ data.tar.gz: 4cdad5268d59c11e83335818bbcdd5627fe3e75045ab2602f84fd0d7440c6d7d
5
5
  SHA512:
6
- metadata.gz: 2dbc0c1b7c6f42f0d4eca33c82b5a7e007ca549dda77b4e4d23056264a16b853b2cacbaa120ff24a1b25eb010aeea79efc955a6f3b9018bf9cca1249276f2410
7
- data.tar.gz: b9e9deb8f5c3faf4a0f5e03757a8070d91e79e1bc959c991ca101df288fb62f809acc15154e7eab234647ad3d9b2d7a2b488b6013ff3a5c6db1978cf06e1654c
6
+ metadata.gz: c9ac4b15042dd07cab99b7be0859e714684073ff4438b8048f33bd9c21779b545d61f1ff17608d1ab15fe2e31a356e2af24df6002d027621958776b42c568db8
7
+ data.tar.gz: afdf6cab6f002f925542831c7e439eace41b9fd4217e8f659d9774e2c7609309ba55e1d1042447d0c091437ab379ca76c0c6fb515c7a90a7720603f1bad68b89
data/README.md CHANGED
@@ -4,7 +4,7 @@ Vi/Vim -inspired experimental GUI-oriented text editor written with Ruby and GTK
4
4
 
5
5
 
6
6
  ## Requirements
7
- - Ruby 2.0+
7
+ - Ruby 3.0+
8
8
  - GTK 4
9
9
 
10
10
  ## Installation
data/demo.txt CHANGED
@@ -15,7 +15,7 @@ Extension .txt can be omitted:
15
15
  ⟦help:keybindings⟧
16
16
 
17
17
  Customizations:
18
- ⟦~/.vimamsa/custom.rb⟧
18
+ ⟦~/.config/vimamsa/custom.rb⟧
19
19
 
20
20
  ◼ Images
21
21
  Images work in .txt-files by drag&drop. (experimental)
data/exe/vimamsa CHANGED
@@ -9,7 +9,7 @@ selfpath = File.readlink(selfpath) if File.lstat(selfpath).symlink?
9
9
  scriptdir = File.expand_path(File.dirname(selfpath) + "/..")
10
10
 
11
11
  # If process is already running, open the parameter file in the running process and exit.
12
- listen_dir = File.expand_path("~/.vimamsa/listen")
12
+ listen_dir = File.expand_path("~/.config/vimamsa/listen")
13
13
  if File.exist?(listen_dir) and !ARGV[0].nil?
14
14
  tmpf = Tempfile.new("vmarun", listen_dir)
15
15
  fp = tmpf.path
@@ -24,6 +24,7 @@ class Buffer < String
24
24
 
25
25
  update_access_time
26
26
  @images = []
27
+ @prefix = prefix
27
28
  @audiofiles = []
28
29
  @lang = nil
29
30
  @id = @@num_buffers
@@ -47,27 +48,10 @@ class Buffer < String
47
48
  @is_parsing_syntax = false
48
49
  @last_update = Time.now - 100
49
50
  @highlights = {}
50
- if fname != nil
51
- @fname = File.expand_path(fname)
52
- detect_file_language()
53
- else
54
- @fname = fname
55
- end
51
+
52
+ set_filename(fname)
56
53
  @hl_queue = []
57
54
  @line_action_handler = nil
58
-
59
- @dirname = nil
60
- @title = "*#{prefix}-#{@id}*"
61
- @subtitle = ""
62
-
63
- if @fname
64
- @title = File.basename(@fname)
65
- @dirname = File.dirname(@fname)
66
- userhome = File.expand_path("~")
67
- # @subtitle = @dirname.gsub(/^#{userhome}/, "~")
68
- @subtitle = @fname.gsub(/^#{userhome}/, "~")
69
- end
70
-
71
55
  t1 = Time.now
72
56
 
73
57
  set_content(str)
@@ -304,7 +288,7 @@ class Buffer < String
304
288
  if is_image_file(fname)
305
289
  debug "Dropped image file"
306
290
  insert_image_after_current_line(fname)
307
- elsif vma.can_open_extension?(fname)
291
+ elsif file_is_text_file(fname)
308
292
  debug "Dropped text file"
309
293
  open_new_file(fname)
310
294
  else
@@ -325,15 +309,10 @@ class Buffer < String
325
309
  self.set_content(str)
326
310
  end
327
311
 
328
- def decrypt(password)
329
- return if @encrypted_str.nil?
330
- begin
331
- @crypt = Encrypt.new(password)
332
- str = @crypt.decrypt(@encrypted_str)
333
- rescue OpenSSL::Cipher::CipherError => e
334
- str = "incorrect password"
335
- end
336
- self.set_content(str)
312
+ def init_encrypted(crypt:, filename:, encrypted:)
313
+ @crypt = crypt
314
+ @encrypted_str = encrypted
315
+ set_filename(filename)
337
316
  end
338
317
 
339
318
  def sanitycheck_btree()
@@ -365,12 +344,6 @@ class Buffer < String
365
344
  @encrypted_str = nil
366
345
  @gui_update_highlight = true
367
346
  @ftype = nil
368
- if str[0..10] == "VMACRYPT001"
369
- @encrypted_str = str[11..-1]
370
- callback = proc { |x| self.decrypt(x) }
371
- gui_one_input_action("Decrypt file \n #{@fname}", "Password:", "decrypt", callback, { :hide => true })
372
- str = "ENCRYPTED"
373
- end
374
347
 
375
348
  if (str[-1] != "\n")
376
349
  str << "\n"
@@ -424,7 +397,10 @@ class Buffer < String
424
397
  end
425
398
 
426
399
  def set_filename(filename)
400
+ debug "set_filename(filename) #{filename}"
427
401
  @fname = filename
402
+ @title = "*#{@prefix}-#{@id}*"
403
+ return if @fname.nil?
428
404
  @pathname = Pathname.new(fname) if @fname
429
405
  @basename = @pathname.basename if @fname
430
406
 
@@ -435,6 +411,7 @@ class Buffer < String
435
411
  vma.buffers.last_dir = @dirname
436
412
 
437
413
  detect_file_language
414
+ gui_set_window_title(@title, @subtitle)
438
415
  end
439
416
 
440
417
  def get_short_path()
@@ -1098,6 +1075,7 @@ class Buffer < String
1098
1075
  else
1099
1076
  wtype = :file
1100
1077
  end
1078
+ word = path
1101
1079
  # elsif hpt_check_cur_word(word) #TODO: check only
1102
1080
  # debug word
1103
1081
  elsif linep != nil
@@ -1111,6 +1089,7 @@ class Buffer < String
1111
1089
  return [fn, :hpt_link]
1112
1090
  end
1113
1091
  end
1092
+
1114
1093
  return [word, wtype]
1115
1094
  end
1116
1095
 
@@ -1268,18 +1247,17 @@ class Buffer < String
1268
1247
  @visual_mode = false
1269
1248
  #TODO: remove @visual_mode
1270
1249
  end
1271
-
1250
+
1272
1251
  def start_selection()
1273
1252
  @selection_start = @pos
1274
1253
  @selection_active = true
1275
1254
  @visual_mode = true
1276
1255
  end
1277
-
1256
+
1278
1257
  # Start selection if not already started
1279
1258
  def continue_selection()
1280
1259
  start_selection if !@selection_active
1281
1260
  end
1282
-
1283
1261
 
1284
1262
  def copy_active_selection(x = nil)
1285
1263
  debug "!COPY SELECTION"
@@ -74,20 +74,35 @@ class Buffer < String
74
74
  set_pos(l.end + 1)
75
75
  end
76
76
 
77
+ # Workaround for https://github.com/ruby-gnome/ruby-gnome/issues/1609
78
+ def paste_start_xclip(at, register)
79
+ @clipboard_paste_running = true
80
+ Thread.new {
81
+ text = `xclip -selection c -o`
82
+ paste_finish(text, at, register)
83
+ }
84
+ return nil
85
+ end
86
+
77
87
  # Start asynchronous read of system clipboard
78
88
  def paste_start(at, register)
79
89
  @clipboard_paste_running = true
90
+
91
+ if true or running_wayland? and !GLib::Version::or_later?(2, 79, 0)
92
+ return paste_start_xclip(at, register)
93
+ end
94
+
80
95
  clipboard = vma.gui.window.display.clipboard
81
96
  clipboard.read_text_async do |_clipboard, result|
82
97
  begin
83
98
  text = clipboard.read_text_finish(result)
84
99
  rescue Gio::IOError::NotSupported
85
- # Happens when pasting from KeePassX and clipboard cleared
86
100
  debug Gio::IOError::NotSupported
87
101
  else
88
102
  paste_finish(text, at, register)
89
103
  end
90
104
  end
105
+ return nil
91
106
  end
92
107
 
93
108
  def paste_finish(text, at, register)
@@ -141,7 +156,7 @@ class Buffer < String
141
156
  return if !is_legal_pos(p)
142
157
  (word, range) = get_word_in_pos(p, boundary: :word)
143
158
  debug [word, range].to_s, 2
144
- endpos = range.begin+rep.size
159
+ endpos = range.begin + rep.size
145
160
  replace_range(range, rep)
146
161
  set_pos(endpos)
147
162
  end
@@ -246,9 +261,9 @@ class Buffer < String
246
261
  end
247
262
 
248
263
  def insert_tab
249
- convert = conf(:tab_to_spaces_default)
250
- convert = true if conf(:tab_to_spaces_languages).include?(@lang)
251
- convert = false if conf(:tab_to_spaces_not_languages).include?(@lang)
264
+ convert = cnf.tab.to_spaces_default?
265
+ convert = true if cnf.tab.to_spaces_languages?.include?(@lang)
266
+ convert = false if cnf.tab.to_spaces_not_languages?.include?(@lang)
252
267
  tw = conf(:tab_width)
253
268
  if convert
254
269
  indent_to = (@cpos / tw) * tw + tw
@@ -65,6 +65,12 @@ class BufferList
65
65
  # TODO: implement using heap/priorityque
66
66
  @list.sort_by! { |x| x.access_time }
67
67
  end
68
+
69
+ def each(&block)
70
+ for x in slist
71
+ block.call(x)
72
+ end
73
+ end
68
74
 
69
75
  def get_last_visited_id
70
76
  last_buf = nil
@@ -1,9 +1,9 @@
1
1
  require "pty"
2
2
 
3
- def handle_drag_and_drop(fname)
4
- debug "EDITOR:handle_drag_and_drop"
5
- buf.handle_drag_and_drop(fname)
6
- end
3
+ # def handle_drag_and_drop(fname)
4
+ # debug "EDITOR:handle_drag_and_drop"
5
+ # buf.handle_drag_and_drop(fname)
6
+ # end
7
7
 
8
8
  class Editor
9
9
  attr_reader :file_content_search_paths, :file_name_search_paths, :gui, :hook, :macro, :actions
@@ -91,23 +91,23 @@ class Editor
91
91
 
92
92
  @gui.init_menu
93
93
 
94
- mkdir_if_not_exists("~/.vimamsa")
95
- mkdir_if_not_exists("~/.vimamsa/backup")
96
- mkdir_if_not_exists("~/.vimamsa/listen")
97
- listen_dir = File.expand_path "~/.vimamsa/listen"
94
+ mkdir_if_not_exists("~/.config/vimamsa")
95
+ mkdir_if_not_exists("~/.config/vimamsa/backup")
96
+ mkdir_if_not_exists("~/.config/vimamsa/listen")
97
+ listen_dir = File.expand_path "~/.config/vimamsa/listen"
98
98
  listener = Listen.to(listen_dir) do |modified, added, removed|
99
99
  debug([modified: modified, added: added, removed: removed])
100
100
  open_file_listener(added)
101
101
  end
102
102
  listener.start
103
103
 
104
- custom_fn = File.expand_path("~/.vimamsa/custom.rb")
104
+ custom_fn = File.expand_path("~/.config/vimamsa/custom.rb")
105
105
  if !File.exist?(custom_fn)
106
106
  example_custom = IO.read(ppath("custom_example.rb"))
107
107
  IO.write(custom_fn, example_custom)
108
108
  end
109
109
 
110
- mkdir_if_not_exists("~/.vimamsa/custom.rb")
110
+ mkdir_if_not_exists("~/.config/vimamsa/custom.rb")
111
111
 
112
112
  $cnf[:theme] = "Twilight_edit"
113
113
  $cnf[:syntax_highlight] = true
@@ -119,7 +119,7 @@ class Editor
119
119
  # set_gui_style(1)
120
120
 
121
121
  #TODO: remove
122
- dotfile = read_file("", "~/.vimamsarc")
122
+ dotfile = read_file("", "~/.config/vimamsarc")
123
123
  eval(dotfile) if dotfile
124
124
 
125
125
  custom_script = read_file("", custom_fn)
@@ -129,9 +129,12 @@ class Editor
129
129
  FileManager.init
130
130
  Autocomplete.init
131
131
 
132
+ if cnf.audio.enabled?
133
+ require "vimamsa/audio"
134
+ end
135
+
132
136
  if cnf.lsp.enabled?
133
137
  require "vimamsa/langservp"
134
- require "vimamsa/audio" # TODO:config
135
138
  @langsrv["ruby"] = LangSrv.new("ruby")
136
139
  @langsrv["cpp"] = LangSrv.new("cpp")
137
140
  end
@@ -287,7 +290,6 @@ end
287
290
 
288
291
  def _quit()
289
292
  vma.shutdown
290
- # Gtk.main_quit
291
293
  end
292
294
 
293
295
  def fatal_error(msg)
@@ -552,6 +554,7 @@ end
552
554
 
553
555
  def jump_to_file(filename, tnum = nil, charn = nil)
554
556
  b = open_new_file(filename)
557
+ return if b.nil?
555
558
  # debug "open_new_file #{filename}, #{tnum} = nil, #{charn}",2
556
559
 
557
560
  # Link to character position
@@ -595,6 +598,10 @@ def open_new_file(filename, file_contents = "")
595
598
  message("File #{filename} does not contain text")
596
599
  return false
597
600
  end
601
+ if Encrypt.is_encrypted?(filename)
602
+ decrypt_dialog(filename: filename)
603
+ return nil
604
+ end
598
605
  message "New file opened: #{filename}"
599
606
  fname = filename
600
607
  bu = load_buffer(fname)
@@ -615,7 +622,7 @@ def hook_draw()
615
622
  end
616
623
 
617
624
  def get_dot_path(sfx)
618
- dot_dir = File.expand_path("~/.vimamsa")
625
+ dot_dir = File.expand_path("~/.config/vimamsa")
619
626
  Dir.mkdir(dot_dir) unless File.exist?(dot_dir)
620
627
  dpath = "#{dot_dir}/#{sfx}"
621
628
  return dpath
@@ -1,6 +1,44 @@
1
1
  require "openssl"
2
2
 
3
+ def decrypt_dialog(filename:, wrong_pass: false)
4
+ callback = proc { |x| Encrypt.open(filename, x) }
5
+ msg = ""
6
+ msg = "\nWRONG PASSWORD!\n" if wrong_pass
7
+ gui_one_input_action("Decrypt file \n #{filename}\n#{msg}", "Password:", "Decrypt", callback, { :hide => true })
8
+ end
9
+
3
10
  class Encrypt
11
+ def self.is_encrypted?(fn)
12
+ debug "self.is_encrypted?(fn)", 2
13
+ begin
14
+ file = File.open(fn, "r")
15
+ first_11_characters = file.read(11)
16
+ return true if first_11_characters == "VMACRYPT001"
17
+ rescue Errno::ENOENT
18
+ puts "File not found: #{file_path}"
19
+ rescue => e
20
+ puts "An error occurred: #{e.message}"
21
+ ensure
22
+ file&.close
23
+ end
24
+ return false
25
+ end
26
+
27
+ def self.open(fn, password)
28
+ debug "open_encrypted(filename,password)", 2
29
+ encrypted = read_file("", fn)[11..-1]
30
+ begin
31
+ crypt = Encrypt.new(password)
32
+ str = crypt.decrypt(encrypted)
33
+ # debug "PASS OK!", 2
34
+ bu = create_new_buffer(str)
35
+ bu.init_encrypted(crypt: crypt, filename: fn, encrypted: encrypted)
36
+ rescue OpenSSL::Cipher::CipherError => e
37
+ # Wrong password
38
+ decrypt_dialog(filename: fn, wrong_pass: true)
39
+ end
40
+ end
41
+
4
42
  def initialize(pass_phrase)
5
43
  salt = "uvgixEtU"
6
44
  @enc = OpenSSL::Cipher.new "AES-128-CBC"
@@ -31,7 +69,6 @@ class Encrypt
31
69
  end
32
70
  end
33
71
 
34
-
35
72
  def encrypt_cur_buffer()
36
73
  callback = proc { |x| encrypt_cur_buffer_callback(x) }
37
74
  gui_one_input_action("Encrypt", "Password:", "Encrypt", callback, { :hide => true })
@@ -123,7 +123,7 @@ class FileManager
123
123
  def cut_file
124
124
  fn = cur_file
125
125
  debug "CUT FILE #{fn}", 2
126
- @cut_files << fn
126
+ @cut_files << fn if !@cut_files.include?(fn)
127
127
  @copied_files = []
128
128
  end
129
129
 
data/lib/vimamsa/gui.rb CHANGED
@@ -8,6 +8,17 @@ def iterate_gui_main_loop
8
8
  GLib::MainContext.default.iteration(true)
9
9
  end
10
10
 
11
+ def start_profiler
12
+ require "ruby-prof"
13
+ RubyProf.start
14
+ end
15
+
16
+ def end_profiler
17
+ result = RubyProf.stop
18
+ printer = RubyProf::FlatPrinter.new(result)
19
+ printer.print(STDOUT)
20
+ end
21
+
11
22
  # Wait for window resize to take effect
12
23
  # GTk3 had a resize notify event which got removed in gtk4
13
24
  # https://discourse.gnome.org/t/gtk4-any-way-to-connect-to-a-window-resize-signal/14869/3
@@ -193,21 +204,6 @@ class VMAgui
193
204
  @img_resizer_active = false
194
205
  @windows = {}
195
206
  @app = nil
196
- # imgproc = proc {
197
- # GLib::Idle.add(proc {
198
- # if !buf.images.empty?
199
- # vma.gui.scale_all_images
200
-
201
- # w = Gtk::Window.new(:toplevel)
202
- # w.set_default_size(1, 1)
203
- # w.show_all
204
- # Thread.new { sleep 0.1; w.destroy }
205
- # end
206
-
207
- # false
208
- # })
209
- # }
210
- # @delex = DelayExecutioner.new(1, imgproc)
211
207
  end
212
208
 
213
209
  def run
@@ -223,18 +219,16 @@ class VMAgui
223
219
  t.exit
224
220
  end
225
221
  end
226
- end
227
-
228
- def delay_scale()
229
- if Time.now - @dtime > 2.0
230
- end
222
+ @app.quit
231
223
  end
232
224
 
233
225
  def scale_all_images
234
- debug "scale all", 2
235
- for img in buf.images
236
- if !img[:obj].destroyed?
237
- img[:obj].scale_image
226
+ for k, window in @windows
227
+ bu = window[:sw].child.bufo
228
+ for img in bu.images
229
+ if !img[:obj].destroyed?
230
+ img[:obj].scale_image
231
+ end
238
232
  end
239
233
  end
240
234
  false
@@ -735,12 +729,28 @@ class VMAgui
735
729
  end
736
730
 
737
731
  # Vimamsa::Menu.new(@menubar) #TODO:gtk4
732
+ GLib::Idle.add(proc { self.monitor })
733
+
738
734
  app.run
739
735
 
740
736
  # @window.show_all
741
737
  # @window.show
742
738
  end
743
739
 
740
+ def monitor
741
+ @monitor_time ||= Time.now
742
+ @sw_width ||= @sw.width
743
+ return true if Time.now - @monitor_time < 0.2
744
+ # Detect element resize
745
+ if @sw.width != @sw_width
746
+ # puts "@sw.width=#{@sw.width}"
747
+ @sw_width = @sw.width
748
+ DelayExecutioner.exec(id: :scale_images, wait: 0.7, callable: proc { vma.gui.scale_all_images })
749
+ end
750
+ @monitor_time = Time.now
751
+ return true
752
+ end
753
+
744
754
  def init_menu
745
755
  Vimamsa::Menu.new(@menubar, @app)
746
756
  end
@@ -755,6 +765,10 @@ class VMAgui
755
765
 
756
766
  def set_one_column
757
767
  return if !@two_column
768
+ #This always closes the leftmost column/window
769
+ #TODO: close rightmost column if left active
770
+ set_active_window(1)
771
+
758
772
  @windows[2][:sw].set_child(nil)
759
773
  @windows.delete(2)
760
774
 
@@ -79,7 +79,6 @@ class VSourceView < GtkSource::View
79
79
  end
80
80
 
81
81
  def set_content(str)
82
- delete_cursorchar
83
82
  self.buffer.set_text(str)
84
83
  end
85
84
 
@@ -123,6 +122,52 @@ class VSourceView < GtkSource::View
123
122
  def register_signals()
124
123
  check_controllers
125
124
 
125
+ # TODO: accept GLib::Type::STRING also?
126
+ @dt = Gtk::DropTarget.new(GLib::Type["GFile"], [Gdk::DragAction::COPY, Gdk::DragAction::MOVE])
127
+ # GLib::Type::INVALID
128
+
129
+ self.add_controller(@dt)
130
+ @dt.signal_connect "drop" do |obj, v, x, y|
131
+ if v.value.gtype == GLib::Type["GLocalFile"]
132
+ uri = v.value.uri
133
+ elsif v.value.class == String
134
+ uri = v.value.gsub(/\r\n$/, "")
135
+ end
136
+ debug "dt,drop #{v.value},#{x},#{y}", 2
137
+ begin
138
+ fp = URI(uri).path
139
+ buf.handle_drag_and_drop(fp)
140
+ rescue URI::InvalidURIError
141
+ end
142
+ true
143
+ end
144
+
145
+ @dt.signal_connect "enter" do |gesture, x, y, z, m|
146
+ debug "dt,enter", 2
147
+ Gdk::DragAction::COPY
148
+ end
149
+
150
+ @dt.signal_connect "motion" do |obj, x, y|
151
+ debug "dt,move", 2
152
+
153
+ Gdk::DragAction::COPY
154
+ end
155
+
156
+ # dc = Gtk::DropControllerMotion.new
157
+ # self.add_controller(dc)
158
+ # dc.signal_connect "enter" do |gesture, x, y|
159
+ # debug "enter", 2
160
+ # debug [x, y]
161
+ # # Ripl.start :binding => binding
162
+ # true
163
+ # end
164
+
165
+ # dc.signal_connect "motion" do |gesture, x, y|
166
+ # debug "move", 2
167
+ # debug [x, y]
168
+ # true
169
+ # end
170
+
126
171
  # Implement mouse selections using @cnt_mo and @cnt_drag
127
172
  @cnt_mo = Gtk::EventControllerMotion.new
128
173
  self.add_controller(@cnt_mo)
@@ -151,7 +196,7 @@ class VSourceView < GtkSource::View
151
196
  debug "Not enough drag", 2
152
197
  buf.end_selection
153
198
  # elsif !buf.visual_mode? and vma.kbd.get_scope != :editor
154
- elsif vma.kbd.get_scope != :editor
199
+ elsif vma.kbd.get_scope != :editor
155
200
  # Can't transition from editor wide mode to buffer specific mode
156
201
  vma.kbd.set_mode(:visual)
157
202
  else
@@ -236,14 +281,12 @@ class VSourceView < GtkSource::View
236
281
 
237
282
  def handle_scrolling()
238
283
  return # TODO
239
- delete_cursorchar
240
284
  # curpos = buffer.cursor_position
241
285
  # debug "MOVE CURSOR: #{curpos}"
242
286
  return nil if vma.gui.nil?
243
287
  return nil if @bufo.nil?
244
288
  vma.gui.run_after_scrolling proc {
245
289
  debug "START UPDATE POS AFTER SCROLLING", 2
246
- delete_cursorchar
247
290
  bc = window_to_buffer_coords(Gtk::TextWindowType::WIDGET, gutter_width + 2, 60)
248
291
  if !bc.nil?
249
292
  i = coord_to_iter(bc[0], bc[1])
@@ -257,7 +300,6 @@ class VSourceView < GtkSource::View
257
300
 
258
301
  def set_cursor_to_top
259
302
  debug "set_cursor_to_top", 2
260
- delete_cursorchar
261
303
  bc = window_to_buffer_coords(Gtk::TextWindowType::WIDGET, gutter_width + 2, 60)
262
304
  if !bc.nil?
263
305
  i = coord_to_iter(bc[0], bc[1])
@@ -270,7 +312,6 @@ class VSourceView < GtkSource::View
270
312
 
271
313
  # def handle_key_event(event, sig)
272
314
  def handle_key_event(keyval, keyname, sig)
273
- delete_cursorchar
274
315
  if $update_cursor
275
316
  handle_scrolling
276
317
  end
@@ -394,7 +435,6 @@ class VSourceView < GtkSource::View
394
435
  end
395
436
 
396
437
  def handle_deltas()
397
- delete_cursorchar
398
438
  any_change = false
399
439
  while d = @bufo.deltas.shift
400
440
  any_change = true
@@ -435,7 +475,6 @@ class VSourceView < GtkSource::View
435
475
  end
436
476
 
437
477
  def set_cursor_pos(pos)
438
- delete_cursorchar
439
478
  itr = buffer.get_iter_at(:offset => pos)
440
479
  itr2 = buffer.get_iter_at(:offset => pos + 1)
441
480
  buffer.place_cursor(itr)
@@ -454,7 +493,7 @@ class VSourceView < GtkSource::View
454
493
  $idle_scroll_to_mark = true
455
494
  ensure_cursor_visible
456
495
 
457
- draw_cursor
496
+ # draw_cursor
458
497
 
459
498
  return true
460
499
  end
@@ -516,18 +555,7 @@ class VSourceView < GtkSource::View
516
555
  end
517
556
  end
518
557
 
519
- # Delete the extra char added to buffer to represent the cursor
520
- def delete_cursorchar
521
- if !@cursorchar.nil?
522
- itr = buffer.get_iter_at(:offset => @cursorchar)
523
- itr2 = buffer.get_iter_at(:offset => @cursorchar + 1)
524
- buffer.delete(itr, itr2)
525
- @cursorchar = nil
526
- end
527
- end
528
-
529
558
  def after_action
530
- delete_cursorchar
531
559
  iterate_gui_main_loop
532
560
  handle_deltas
533
561
  iterate_gui_main_loop
@@ -543,7 +571,8 @@ class VSourceView < GtkSource::View
543
571
  self.style_context.remove_provider(@cursor_prov)
544
572
  end
545
573
  prov = Gtk::CssProvider.new
546
- prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; }")
574
+ # prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; }")
575
+ prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; } .view { caret-color: #{bg}; }")
547
576
  self.style_context.add_provider(prov)
548
577
  @cursor_prov = prov
549
578
  end
@@ -557,40 +586,29 @@ class VSourceView < GtkSource::View
557
586
  # @tt.font = "Arial"
558
587
  # end
559
588
 
589
+ sv = vma.gui.sw.child
590
+ return if sv.nil? #TODO: should not happen?
560
591
  mode = vma.kbd.get_mode
561
592
  ctype = vma.kbd.get_cursor_type
562
593
  ctype = :visual if vma.buf.selection_active?
563
594
 
564
- delete_cursorchar
565
595
  vma.gui.remove_overlay_cursor
566
596
  if [:command, :replace, :browse].include?(ctype)
567
597
  set_cursor_color(ctype)
568
- if @bufo[@bufo.pos] == "\n"
569
- # If we are at end of line, it's not possible to draw the cursor by making a selection. I tried to do this by drawing an overlay, but that generates issues. If moving the cursor causes the ScrolledWindow to be scrolled, these errors randomly appear and the whole view shows blank:
570
- # (ruby:21016): Gtk-WARNING **: 19:52:23.181: Trying to snapshot GtkSourceView 0x55a97524c8c0 without a current allocation
571
- # (ruby:21016): Gtk-WARNING **: 19:52:23.181: Trying to snapshot GtkGizmo 0x55a9727d2580 without a current allocation
572
- # (ruby:21016): Gtk-WARNING **: 19:52:23.243: Trying to snapshot GtkSourceView 0x55a97524c8c0 without a current allocation
573
- # vma.gui.overlay_draw_cursor(@bufo.pos)
574
-
575
- # Current workaround is to add an empty space to the place where the cursor is and then remove this whenever we get any kind of event that might cause this class to be accessed.
576
- itr = buffer.get_iter_at(:offset => @bufo.pos)
577
- buffer.insert(itr, " ") # normal space
578
- # buffer.insert(itr, " ") # thin space (U+2009)
579
- # buffer.insert(itr, "l")
580
- @cursorchar = @bufo.pos
581
-
582
- # Apparently we need to redo this after buffer.insert:
583
- itr = buffer.get_iter_at(:offset => @bufo.pos)
584
- itr2 = buffer.get_iter_at(:offset => @bufo.pos + 1)
585
- # buffer.apply_tag(@tt, itr, itr2)
586
- buffer.select_range(itr, itr2)
587
- else
588
- itr = buffer.get_iter_at(:offset => @bufo.pos)
589
- itr2 = buffer.get_iter_at(:offset => @bufo.pos + 1)
590
- buffer.select_range(itr, itr2)
591
- end
592
- # elsif @bufo.visual_mode?
593
598
 
599
+ sv.overwrite = true
600
+ # sv.cursor_visible = true
601
+ # sv.reset_cursor_blink
602
+
603
+ # (Via trial and error) This combination is needed to make cursor visible:
604
+ sv.cursor_visible = false
605
+ sv.cursor_visible = true
606
+
607
+ # sv.reset_cursor_blink
608
+ Gtk::Settings.default.gtk_cursor_blink = false
609
+ # Gtk::Settings.default.gtk_cursor_blink_time = 8000
610
+ # vma.gui.sw.child.toggle_cursor_visible
611
+ # vma.gui.sw.child.cursor_visible = true
594
612
  elsif ctype == :visual
595
613
  set_cursor_color(ctype)
596
614
  # debug "VISUAL MODE"
@@ -601,16 +619,19 @@ class VSourceView < GtkSource::View
601
619
  # Pango-CRITICAL **: pango_layout_get_cursor_pos: assertion 'index >= 0 && index <= layout->length' failed
602
620
  buffer.select_range(itr, itr2)
603
621
  elsif ctype == :insert
604
- # Not sure why this is needed
605
- itr = buffer.get_iter_at(:offset => @bufo.pos)
606
- buffer.select_range(itr, itr)
607
-
608
- # Via trial and error, this combination is only thing that seems to work:
609
- vma.gui.sw.child.toggle_cursor_visible
610
- vma.gui.sw.child.cursor_visible = true
611
-
622
+ set_cursor_color(ctype)
623
+ sv.overwrite = false
624
+ # sv.cursor_visible = false
625
+ # sv.cursor_visible = true
612
626
  debug "INSERT MODE"
613
627
  else # TODO
614
628
  end
629
+ if [:insert, :command, :replace, :browse].include?(ctype)
630
+ # Place cursor where it already is
631
+ # Without this hack, the cursor doesn't always get drawn
632
+ pos = @bufo.pos
633
+ itr = buffer.get_iter_at(:offset => pos)
634
+ buffer.place_cursor(itr)
635
+ end
615
636
  end
616
637
  end
@@ -24,7 +24,9 @@ class Autocomplete
24
24
 
25
25
  def self.add_words(words)
26
26
  for w in words
27
- @@trie << w
27
+ if w.size < 100
28
+ @@trie << w
29
+ end
28
30
  end
29
31
  end
30
32
 
@@ -7,7 +7,7 @@ def hpt_check_cur_word(w)
7
7
  dn = File.dirname(vma.buf.fname)
8
8
 
9
9
  fcands = []
10
- if fpfx[0] != "/"
10
+ if fpfx[0] != "/" and fpfx[0] != "~"
11
11
  fcands << "#{dn}/#{fpfx}"
12
12
  fcands << "#{dn}/#{fpfx}.txt"
13
13
  end
@@ -26,7 +26,7 @@ def hpt_check_cur_word(w)
26
26
  if fn
27
27
  if m[2] == "audio"
28
28
  # Thread.new { Audio.play(fn) }
29
- Audio.play(fn)
29
+ Audio.play(fn) if cnf.audio.enabled?
30
30
  else
31
31
  if !file_is_text_file(fn)
32
32
  message "Not text file #{fn}"
@@ -52,6 +52,7 @@ def hpt_check_cur_word(w)
52
52
  return nil
53
53
  end
54
54
 
55
+
55
56
  def hpt_create_new_file(fn)
56
57
  create_new_file(fn)
57
58
  end
@@ -128,7 +129,7 @@ def hpt_scan_images(bf = nil)
128
129
  }
129
130
 
130
131
  # Need to scale after buffer loaded
131
- GLib::Idle.add(proc { vma.gui.scale_all_images })
132
+ run_as_idle proc { vma.gui.scale_all_images }
132
133
 
133
134
  # vma.gui.delex.run #TODO:gtk4
134
135
  end
@@ -17,6 +17,7 @@ cnf.mode.default.cursor.background = "#03fcca"
17
17
  cnf.mode.visual.cursor.background = "#bc6040"
18
18
  cnf.mode.replace.cursor.background = "#fc0331"
19
19
  cnf.mode.browse.cursor.background = "#f803fc"
20
+ cnf.mode.insert.cursor.background = "#ffffff"
20
21
 
21
22
  def _insert_move(op)
22
23
  if op == :pagedown
@@ -332,6 +333,7 @@ default_keys = {
332
333
  "CV , R" => "restart_application",
333
334
  # "I ctrl!" => "vma.kbd.to_previous_mode",
334
335
  "C shift!" => "buf.save",
336
+ "I ctrl-s" => "buf.save",
335
337
  "I <char>" => "buf.insert_txt(<char>)",
336
338
  "I esc || I ctrl!" => "vma.kbd.to_previous_mode",
337
339
 
data/lib/vimamsa/macro.rb CHANGED
@@ -165,7 +165,7 @@ class Macro
165
165
  m = @recorded_macros[name]
166
166
  return if !(m.kind_of?(Array) and m.any?)
167
167
  contents = m.join(";")
168
- dot_dir = File.expand_path("~/.vimamsa")
168
+ dot_dir = File.expand_path("~/.config/.vimamsa")
169
169
  Dir.mkdir(dot_dir) unless File.exist?(dot_dir)
170
170
  save_fn = "#{dot_dir}/macro_#{name}.rb"
171
171
 
data/lib/vimamsa/rbvma.rb CHANGED
@@ -1,3 +1,5 @@
1
+
2
+ # require "bundler/setup"
1
3
  require "date"
2
4
  require "fileutils"
3
5
 
data/lib/vimamsa/util.rb CHANGED
@@ -3,6 +3,18 @@ require "open3"
3
3
  VOWELS = %w(a e i o u)
4
4
  CONSONANTS = %w(b c d f g h j k l m n p q r s t v w x y z)
5
5
 
6
+ def running_wayland?
7
+ sess = ENV["DESKTOP_SESSION"]
8
+ sess ||= ENV["XDG_SESSION_DESKTOP"]
9
+ sess ||= ENV["GDMSESSION"]
10
+ sess ||= ""
11
+ if sess.match(/wayland/)
12
+ return true
13
+ else
14
+ return false
15
+ end
16
+ end
17
+
6
18
  def tilde_path(abspath)
7
19
  userhome = File.expand_path("~/")
8
20
  abspath.sub(/^#{Regexp.escape(userhome)}\//, "~/")
@@ -46,13 +58,16 @@ end
46
58
 
47
59
  def file_mime_type(fpath)
48
60
  fpath = File.expand_path(fpath)
49
- return false if !File.readable?(fpath)
61
+ return nil if !File.readable?(fpath)
50
62
  r = exec_cmd("file", "--mime-type", "--mime-encoding", fpath)
51
- return false if r.class != String
52
- return false if r.size < 2
63
+ return nil if r.class != String
64
+ return nil if r.size < 2
53
65
  m = r.match(".*:\s*(.*)")
54
- mimetype = m[1].match(/(.*);/)
55
- charset = m[1].match(/charset=(.*)/)
66
+ b = m[1].match(/(.*);/)
67
+ c = m[1].match(/charset=(.*)/)
68
+ return nil if b.nil? or c.nil?
69
+ mimetype = b[1]
70
+ charset = c[1]
56
71
  return [mimetype, charset]
57
72
  end
58
73
 
@@ -185,6 +200,17 @@ end
185
200
  # Used for image scaling after window resize
186
201
 
187
202
  class DelayExecutioner
203
+
204
+ # Run 'callable.call' if 'wait' time elapsed from last exec call for this id
205
+ def self.exec(id:, wait:, callable:)
206
+ @@h ||= {}
207
+ h = @@h
208
+ if h[id].nil?
209
+ h[id] = DelayExecutioner.new(wait, callable)
210
+ end
211
+ h[id].run
212
+ end
213
+
188
214
  def initialize(wait_time, _proc)
189
215
  @wait_time = wait_time
190
216
  @proc = _proc
@@ -206,7 +232,10 @@ class DelayExecutioner
206
232
  end
207
233
 
208
234
  def run()
235
+ # Reset @lastt to further delay execution until @wait_time from now
209
236
  @lastt = Time.now
237
+
238
+ # If already executed after last call to run()
210
239
  if @thread_running == false
211
240
  @thread_running = true
212
241
  start_thread
@@ -299,17 +328,22 @@ end
299
328
 
300
329
  def is_image_file(fpath)
301
330
  return false if !File.exist?(fpath)
302
- return false if !fpath.match(/.(jpg|jpeg|png)$/i)
303
- #TODO: check contents of file
304
- return true
331
+ # return false if !fpath.match(/.(jpg|jpeg|png)$/i)
332
+ mime = file_mime_type(fpath)
333
+ if !mime.nil?
334
+ if mime[0].match(/image\//)
335
+ return true
336
+ end
337
+ end
338
+ return false
305
339
  end
306
340
 
307
- def is_text_file(fpath)
308
- return false if !File.exist?(fpath)
309
- return false if !fpath.match(/.(txt|cpp|h|rb|c|php|java|py)$/i)
310
- #TODO: check contents of file
311
- return true
312
- end
341
+ # def is_text_file(fpath)
342
+ # return false if !File.exist?(fpath)
343
+ # return false if !fpath.match(/.(txt|cpp|h|rb|c|php|java|py)$/i)
344
+ # #TODO: check contents of file
345
+ # return true
346
+ # end
313
347
 
314
348
  def is_path(s)
315
349
  m = s.match(/(~[a-z]*)?\/.*\//)
@@ -1,3 +1,3 @@
1
1
  module Vimamsa
2
- VERSION = "0.1.17"
2
+ VERSION = "0.1.19"
3
3
  end
data/vimamsa.gemspec CHANGED
@@ -27,16 +27,16 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_runtime_dependency 'ripl', '~> 0.7.1'
29
29
  spec.add_runtime_dependency 'ripl-multi_line', '~> 0.3.1'
30
- spec.add_runtime_dependency 'gdk4', '~> 4.2.0'
31
- spec.add_runtime_dependency 'gtk4', '~> 4.2.0'
30
+ spec.add_runtime_dependency 'gdk4', '~> 4.2.1'
31
+ spec.add_runtime_dependency 'gtk4', '~> 4.2.1'
32
+ spec.add_runtime_dependency 'gtksourceview5', '~> 4.2.1'
33
+ spec.add_runtime_dependency 'gstreamer', '~> 4.2.1'
32
34
  spec.add_runtime_dependency 'rambling-trie', '~> 2.3.1'
33
35
 
34
36
  spec.add_runtime_dependency 'differ', '~> 0.1.2'
35
- spec.add_runtime_dependency 'gtksourceview5', '~> 4.2.0'
36
37
  spec.add_runtime_dependency 'parallel', '~> 1.14' #TODO: update?
37
38
  spec.add_runtime_dependency 'listen', '~> 3.4' #TODO: update?
38
39
  spec.add_runtime_dependency 'language_server-protocol', '~> 3.17.0.3'
39
- spec.add_runtime_dependency 'gstreamer', '~> 4.2.0'
40
40
 
41
41
  spec.extensions = ["ext/vmaext/extconf.rb"]
42
42
  spec.licenses = ['GPL-3.0+']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vimamsa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.17
4
+ version: 0.1.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sami Sieranoja
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-26 00:00:00.000000000 Z
11
+ date: 2024-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,126 +86,126 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 4.2.0
89
+ version: 4.2.1
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 4.2.0
96
+ version: 4.2.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: gtk4
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 4.2.0
103
+ version: 4.2.1
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 4.2.0
110
+ version: 4.2.1
111
111
  - !ruby/object:Gem::Dependency
112
- name: rambling-trie
112
+ name: gtksourceview5
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 2.3.1
117
+ version: 4.2.1
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 2.3.1
124
+ version: 4.2.1
125
125
  - !ruby/object:Gem::Dependency
126
- name: differ
126
+ name: gstreamer
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.1.2
131
+ version: 4.2.1
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.1.2
138
+ version: 4.2.1
139
139
  - !ruby/object:Gem::Dependency
140
- name: gtksourceview5
140
+ name: rambling-trie
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 4.2.0
145
+ version: 2.3.1
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 4.2.0
152
+ version: 2.3.1
153
153
  - !ruby/object:Gem::Dependency
154
- name: parallel
154
+ name: differ
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '1.14'
159
+ version: 0.1.2
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '1.14'
166
+ version: 0.1.2
167
167
  - !ruby/object:Gem::Dependency
168
- name: listen
168
+ name: parallel
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: '3.4'
173
+ version: '1.14'
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: '3.4'
180
+ version: '1.14'
181
181
  - !ruby/object:Gem::Dependency
182
- name: language_server-protocol
182
+ name: listen
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 3.17.0.3
187
+ version: '3.4'
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: 3.17.0.3
194
+ version: '3.4'
195
195
  - !ruby/object:Gem::Dependency
196
- name: gstreamer
196
+ name: language_server-protocol
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 4.2.0
201
+ version: 3.17.0.3
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 4.2.0
208
+ version: 3.17.0.3
209
209
  description: Vi/Vim -inspired experimental GUI-oriented text editor written with Ruby
210
210
  and GTK.
211
211
  email:
@@ -298,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
298
  - !ruby/object:Gem::Version
299
299
  version: '0'
300
300
  requirements: []
301
- rubygems_version: 3.2.3
301
+ rubygems_version: 3.3.26
302
302
  signing_key:
303
303
  specification_version: 4
304
304
  summary: Vimamsa