vimamsa 0.1.19 → 0.1.21

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d29e057a168e6c2152c0d8da4c6957b863bd44e7dd9328ba2d5520ae11ab49a2
4
- data.tar.gz: 4cdad5268d59c11e83335818bbcdd5627fe3e75045ab2602f84fd0d7440c6d7d
3
+ metadata.gz: 4b44f279b048a7cd7baba9e21e70dc9666a251f9608466f9e4bd38094c486738
4
+ data.tar.gz: ef57b1ad00c480d30720ec8d272df38ec289640c7951b8a04a070837e43a261a
5
5
  SHA512:
6
- metadata.gz: c9ac4b15042dd07cab99b7be0859e714684073ff4438b8048f33bd9c21779b545d61f1ff17608d1ab15fe2e31a356e2af24df6002d027621958776b42c568db8
7
- data.tar.gz: afdf6cab6f002f925542831c7e439eace41b9fd4217e8f659d9774e2c7609309ba55e1d1042447d0c091437ab379ca76c0c6fb515c7a90a7720603f1bad68b89
6
+ metadata.gz: 756f7c861bff64427fac5e397f8e0b4d539f46dd9d72edf39ddbc190eefff09cb86c0107ec38664ee9a1c450c2de9912f6960aee7c990c8b99c4c914cf0f5a56
7
+ data.tar.gz: 15a6b06c01f13435a154a2b64c544e8d5b14f253bed3e4b65e845dc510f591fcd77c1e9c278d4cf7b67699205c97952ad6ab8042fffe222260d972b88db42bee
data/README.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # Vimamsa
2
2
 
3
- Vi/Vim -inspired experimental GUI-oriented text editor written with Ruby and GTK.
3
+ Vi/Vim -inspired experimental GUI-oriented text editor written with Ruby and GTK.
4
4
 
5
+ <!-- toc -->
6
+
7
+ - [Requirements](#requirements)
8
+ - [Installation](#installation)
9
+ * [Other install options](#other-install-options)
10
+ - [Run](#run)
11
+ - [Screenshots](#screenshots)
12
+ - [Key bindings](#key-bindings)
13
+ - [Current limitations](#current-limitations)
14
+
15
+ <!-- tocstop -->
5
16
 
6
17
  ## Requirements
7
18
  - Ruby 3.0+
@@ -144,6 +155,10 @@ For example, to bind ctrl-n to action "create new file":
144
155
  bindkey 'C ctrl-n', 'create_new_file()'
145
156
  ```
146
157
 
158
+
159
+ ## Known issues
160
+ - Cursor sometimes vanishes when dragging or resizing the window. At least some cases are fixed in new GTK4 versions ( >= 4.18, in Ubuntu Ubuntu 25.04). Workaround is to press ctrl key twice.
161
+
147
162
  ## Current limitations
148
163
  - UTF8 only
149
164
  - Line endings with "\n"
data/custom_example.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  # c = Converter.new(lambda { |x| h = {}; x.split(/\s+/).each { |y| h[y] = 1 }; h.keys.join(" ") }, :lambda, :uniqwords)
5
5
 
6
6
  # Eval selected text as ruby code (e.g. use as calculator)
7
+
7
8
  # bindkey "V , e", "vma.buf.convert_selected_text(:eval)"
8
9
  # syntax: bindkey "mode key1 key2 ..."
9
10
 
@@ -26,7 +27,6 @@
26
27
 
27
28
 
28
29
 
29
-
30
30
  def insert_date()
31
31
  # $buffer.insert_txt("#{DateTime.now().strftime("==========\n%Y-%m-%d")}\n")
32
32
  vma.buf.insert_txt("#{DateTime.now().strftime("%Y-%m-%d")}\n")
@@ -6,6 +6,11 @@ require 'mkmf'
6
6
  module_name = "vimamsa"
7
7
  extension_name = 'vmaext'
8
8
 
9
+ # $CFLAGS << " -Wall -fpermissive "
10
+ # $CXXFLAGS << " -Wall -fpermissive "
11
+
12
+ # have_library( 'stdc++' );
13
+
9
14
  dir_config(extension_name) # The destination
10
15
  create_makefile(extension_name) # Create Makefile
11
16
 
data/lib/vimamsa/ack.rb CHANGED
@@ -4,21 +4,13 @@ class FileContentSearch
4
4
  def self.start_gui()
5
5
  search_paths = vma.get_content_search_paths.join("<br/>")
6
6
 
7
- nfo = "<span size='x-large'>Search contents of text files</span>
8
- Will search all .txt files in the following directories:
9
- #{search_paths}
10
-
11
- <span>Hint: add empty file named .vma_project to directories you want to search in.
12
- If .vma_project exists in parent directory of current file, searches within that directory.
13
- </span>"
14
-
15
7
  callback = proc { |x| FileContentSearch.search_buffer(x) }
16
8
 
17
9
  params = {}
18
10
  params["inputs"] = {}
19
11
  params["inputs"]["search"] = { :label => "Search:", :type => :entry }
20
12
  params["inputs"]["extensions"] = { :label => "Limit to file extensions:", :type => :entry }
21
- params["inputs"]["extensions"][:initial_text] = conf(:default_search_extensions).join(",")
13
+ params["inputs"]["extensions"][:initial_text] = cnf.default_search_extensions!.join(",")
22
14
  params["inputs"]["btn1"] = { :label => "Search", :type => :button }
23
15
 
24
16
  params[:callback] = callback
@@ -92,17 +84,12 @@ end
92
84
  def gui_ack()
93
85
  search_paths = vma.get_content_search_paths.join("<br/>")
94
86
 
95
- nfo = "<html><h2>Search contents of all files using ack</h2>
96
- <div style='width:300px'>
97
- <p>Hint: add empty file named .vma_project to dirs you want to search.</p>\n<p>If .vma_project exists in parent dir of current file, searches within that dir</p></div></html>"
98
-
99
87
  nfo = "<span size='x-large'>Search contents of all files using ack</span>
100
88
  Will search the following directories:
101
89
  #{search_paths}
102
90
 
103
- <span>Hint: add empty file named .vma_project to directories you want to search in.
104
- If .vma_project exists in parent directory of current file, searches within that directory.
105
- </span>"
91
+ <span>Note: Directory determined automatically as the first parent directory of a last accessed file which includes file/dir named .git or .vma_project. Or, if not found, the last accessed directory.
92
+ </span>"
106
93
 
107
94
  callback = proc { |x| Ack.new.ack_buffer(x) }
108
95
  gui_one_input_action(nfo, "Search:", "search", callback)
@@ -151,6 +138,10 @@ class Ack
151
138
  end
152
139
 
153
140
  def ack_buffer(_instr, b = nil)
141
+ if _instr.nil? or _instr.strip.size <= 1
142
+ message("No input for ack")
143
+ return
144
+ end
154
145
  instr = Shellwords.escape(_instr)
155
146
  bufstr = ""
156
147
  for path in vma.get_content_search_paths
@@ -41,6 +41,7 @@ class Buffer < String
41
41
  @module = nil
42
42
 
43
43
  @last_save = @last_asked_from_user = @file_last_cheked = Time.now
44
+ @t_modified = @last_save
44
45
 
45
46
  @crypt = nil
46
47
  @update_highlight = true
@@ -271,7 +272,7 @@ class Buffer < String
271
272
 
272
273
  def unindent
273
274
  debug("unindent", 2)
274
- conf(:tab_width).times {
275
+ cnf.tab.width!.times {
275
276
  p = @pos - 1
276
277
  if p >= 0
277
278
  if self[p] == " "
@@ -754,7 +755,7 @@ class Buffer < String
754
755
  end
755
756
 
756
757
  def update_highlights(pos, changeamount, changestr)
757
- return if !self.is_highlighted # $cnf[:syntax_highlight]
758
+ return if !self.is_highlighted
758
759
  lpos, cpos = get_line_and_col_pos(pos)
759
760
  if @highlights and @highlights[lpos]
760
761
  hl = @highlights[lpos]
@@ -1063,7 +1064,11 @@ class Buffer < String
1063
1064
  # message("Open link #{word}")
1064
1065
  linep = get_file_line_pointer(word)
1065
1066
  debug "linep'#{linep}'"
1066
- path = File.expand_path(word)
1067
+ if word[0] != "/" and word[0] != "~"
1068
+ path = File.expand_path("#{bufs.last_dir}/#{word}")
1069
+ else
1070
+ path = File.expand_path(word)
1071
+ end
1067
1072
  wtype = nil
1068
1073
  if is_url(word)
1069
1074
  wtype = :url
@@ -1089,7 +1094,7 @@ class Buffer < String
1089
1094
  return [fn, :hpt_link]
1090
1095
  end
1091
1096
  end
1092
-
1097
+
1093
1098
  return [word, wtype]
1094
1099
  end
1095
1100
 
@@ -1158,7 +1163,7 @@ class Buffer < String
1158
1163
  c = c.force_encoding("UTF-8"); #TODO:correct?
1159
1164
 
1160
1165
  c = "\n" if c == "\r"
1161
- if $cnf[:indent_based_on_last_line] and c == "\n" and @lpos > 0
1166
+ if cnf.indent_based_on_last_line? and c == "\n" and @lpos > 0
1162
1167
  # Indent start of new line based on last line
1163
1168
  last_line = line(@lpos)
1164
1169
  m = /^( +)([^ ]+|$)/.match(last_line)
@@ -1291,6 +1296,16 @@ class Buffer < String
1291
1296
  end_visual_mode
1292
1297
  end
1293
1298
 
1299
+ def eval_whole_buf(x = 888)
1300
+ s = self.to_s
1301
+ begin
1302
+ eval(s)
1303
+ rescue Exception
1304
+ message("Error running eval")
1305
+ else
1306
+ end
1307
+ end
1308
+
1294
1309
  def convert_selected_text(converter_id)
1295
1310
  return if !@visual_mode
1296
1311
  r = get_visual_mode_range
@@ -1499,6 +1514,7 @@ class Buffer < String
1499
1514
  #TODO: show message box
1500
1515
  end
1501
1516
  @last_save = Time.now
1517
+ refresh_title
1502
1518
  debug "file saved on #{@last_save}"
1503
1519
  sleep 3
1504
1520
  }
@@ -1511,6 +1527,20 @@ class Buffer < String
1511
1527
  end
1512
1528
  end
1513
1529
 
1530
+ def unsaved_changes?
1531
+ pp [@t_modified, @last_save]
1532
+ return true if @t_modified > @last_save
1533
+ return false
1534
+ end
1535
+
1536
+ def refresh_title
1537
+ if vma.buf == self
1538
+ pfx = ""
1539
+ pfx = "+ " if vma.buf.unsaved_changes?
1540
+ gui_set_window_title(pfx + vma.buf.title, vma.buf.subtitle)
1541
+ end
1542
+ end
1543
+
1514
1544
  def check_if_modified_outside
1515
1545
  # Don't check if less than 8 seconds since last checked
1516
1546
  return false if @fname.nil?
@@ -5,6 +5,7 @@ class Buffer < String
5
5
 
6
6
  #TODO: change to apply=true as default
7
7
  def add_delta(delta, apply = false, auto_update_cpos = false)
8
+ @t_modified = Time.now
8
9
  return if !is_delta_ok(delta)
9
10
  if delta[1] == DELETE
10
11
  return if delta[0] >= self.size
@@ -26,6 +27,7 @@ class Buffer < String
26
27
  add_delta([self.size, INSERT, 1, "\n"], true)
27
28
  end
28
29
  reset_larger_cpos #TODO: correct here?
30
+ refresh_title
29
31
  end
30
32
 
31
33
  # TODO: rename ot auto-format. separate module?
@@ -264,7 +266,7 @@ class Buffer < String
264
266
  convert = cnf.tab.to_spaces_default?
265
267
  convert = true if cnf.tab.to_spaces_languages?.include?(@lang)
266
268
  convert = false if cnf.tab.to_spaces_not_languages?.include?(@lang)
267
- tw = conf(:tab_width)
269
+ tw = cnf.tab.width!
268
270
  if convert
269
271
  indent_to = (@cpos / tw) * tw + tw
270
272
  indentdiff = indent_to - @cpos
@@ -65,7 +65,7 @@ class BufferList
65
65
  # TODO: implement using heap/priorityque
66
66
  @list.sort_by! { |x| x.access_time }
67
67
  end
68
-
68
+
69
69
  def each(&block)
70
70
  for x in slist
71
71
  block.call(x)
@@ -154,7 +154,7 @@ class BufferList
154
154
  # end
155
155
  # vma.kbd.set_mode_to_default if vma.kbd.get_scope != :editor
156
156
 
157
- gui_set_window_title(vma.buf.title, vma.buf.subtitle)
157
+ vma.buf.refresh_title
158
158
 
159
159
  if vma.buf.fname
160
160
  @last_dir = File.dirname(vma.buf.fname)
@@ -187,21 +187,55 @@ class BufferList
187
187
  @navigation_idx = 0
188
188
  end
189
189
 
190
- def history_switch_backwards
191
- @navigation_idx += 1
190
+ def history_switch(dir = -1)
191
+ # -1: from newest towards oldest
192
+ # +1: from oldest towards newest
193
+
194
+ @navigation_idx += dir * -1
192
195
  @navigation_idx = 0 if @navigation_idx >= list.size
196
+ @navigation_idx = list.size - 1 if @navigation_idx < 0
197
+
198
+ # most recent is at end of slist
193
199
  b = slist[-1 - @navigation_idx]
194
- debug "IND:#{@navigation_idx} RECENT:#{slist.collect { |x| x.fname }.join(" ")}"
200
+ puts "@navigation_idx=#{@navigation_idx}"
201
+ non_active = slist.select{|x|!x.is_active?}
202
+ return if non_active.size == 0
203
+
204
+ # Take another one from the history if buffer is already open in a window (active)
205
+ navtmp = @navigation_idx
206
+ i = 1
207
+ while b.is_active?
208
+ pp "b.is_active b=#{b.id}"
209
+ navtmp += dir * -1
210
+ b = slist[-1 - navtmp]
211
+ if b.nil? # went past the beginning or end of array slist
212
+ # Start from the end
213
+ if navtmp != 0 and dir == -1 # did not already start from the end
214
+ navtmp = 0
215
+ i = 0
216
+ b = slist[-1 - navtmp]
217
+ elsif navtmp == list.size and dir == 1
218
+ navtmp = list.size
219
+ i = 0
220
+ b = slist[-1 - navtmp]
221
+ else
222
+ return # No buffer exists which is not active already
223
+ end
224
+ end
225
+ i += 1
226
+ end
227
+ @navigation_idx = navtmp
228
+
229
+ pp "IND:#{@navigation_idx} RECENT:#{slist.collect { |x| x.fname }.join("\n")}"
195
230
  set_current_buffer(b.id, false)
196
231
  end
197
232
 
198
- def history_switch_forwards()
199
- @navigation_idx -= 1
200
- @navigation_idx = list.size - 1 if @navigation_idx < 0
233
+ def history_switch_backwards()
234
+ history_switch(-1)
235
+ end
201
236
 
202
- b = slist[-1 - @navigation_idx]
203
- debug "IND:#{@navigation_idx} RECENT:#{slist.collect { |x| x.fname }.join(" ")}"
204
- set_current_buffer(b.id, false)
237
+ def history_switch_forwards()
238
+ history_switch(+1)
205
239
  end
206
240
 
207
241
  def get_last_non_active_buffer
data/lib/vimamsa/conf.rb CHANGED
@@ -1,43 +1,36 @@
1
- $cnf = {} # TODO
2
1
 
3
- def conf(id)
4
- return $cnf[id]
5
- end
6
-
7
- def set_conf(id, val)
8
- $cnf[id] = val
9
- end
10
-
11
- def setcnf(id, val)
12
- set_conf(id, val)
13
- end
14
-
15
- setcnf :custom_lsp, {}
16
-
17
- setcnf :indent_based_on_last_line, true
18
- setcnf :extensions_to_open, [".txt", ".h", ".c", ".cpp", ".hpp", ".rb", ".inc", ".php", ".sh", ".m", ".gd", ".js", ".py"]
19
- setcnf :default_search_extensions, ["txt", "rb"]
20
-
21
- setcnf "log.verbose", 1
22
- setcnf :enable_lsp, false
23
-
24
- setcnf :tab_width, 2
25
- setcnf :tab_to_spaces_default, false
26
- setcnf :tab_to_spaces_languages, ["c", "java", "ruby", "hyperplaintext", "php"]
27
- setcnf :tab_to_spaces_not_languages, ["makefile"]
28
-
29
- setcnf :workspace_folders, []
30
-
31
-
32
- # New way to configure:
33
- # To set conf value:
2
+ # Set conf value by:
34
3
  # cnf.foo.bar.baz = 3
35
4
 
36
- #To get conf value:
5
+ # Get conf value by:
37
6
  # cnf.foo.bar.baz?
38
7
  # cnf.foo.bar.baz!
39
8
  # get(cnf.foo.bar.baz)
40
- # (All get the same result)
9
+ # (All ways get the same result)
10
+
11
+ $confh = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
12
+ # set cnf.foo.bar.baz, 3
13
+ # => $confh = {:foo=>{:bar=>{:baz=>3}}}
14
+ def set(_id, val)
15
+ a = $confh
16
+ id = _id.to_a
17
+ last = id.pop
18
+ for x in id
19
+ a = a[x]
20
+ end
21
+ a[last] = val
22
+ end
23
+
24
+ def get(id)
25
+ id = id.to_a
26
+ a = $confh
27
+ for x in id
28
+ return nil if a[x].nil?
29
+ return nil if a.empty?
30
+ a = a[x]
31
+ end
32
+ return a
33
+ end
41
34
 
42
35
  class ConfId
43
36
  def initialize(first)
@@ -104,32 +97,6 @@ class Conf
104
97
  end
105
98
  end
106
99
 
107
-
108
-
109
- $confh = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
110
- # set cnf.foo.bar.baz, 3
111
- # => $confh = {:foo=>{:bar=>{:baz=>3}}}
112
- def set(_id, val)
113
- a = $confh
114
- id = _id.to_a
115
- last = id.pop
116
- for x in id
117
- a = a[x]
118
- end
119
- a[last] = val
120
- end
121
-
122
- def get(id)
123
- id = id.to_a
124
- a = $confh
125
- for x in id
126
- return nil if a[x].nil?
127
- return nil if a.empty?
128
- a = a[x]
129
- end
130
- return a
131
- end
132
-
133
100
  $vimamsa_conf = Conf.new
134
101
 
135
102
  def cnf()
@@ -158,6 +125,7 @@ cnf.lsp.enabled = false
158
125
  cnf.font.size = 11
159
126
  cnf.font.family = "Monospace"
160
127
 
128
+ cnf.startup_file=false
161
129
 
162
130
  cnf.macro.animation_delay = 0.02
163
131
 
data/lib/vimamsa/debug.rb CHANGED
@@ -63,7 +63,7 @@ def savedebug(message, e)
63
63
  dbginfo["trace"] = e.backtrace() if e
64
64
  dbginfo["trace_str"] = dbginfo["trace"].join("\n")
65
65
  dbginfo["edit_history"] = buf.edit_history
66
- dbginfo["cnf"] = $cnf
66
+ dbginfo["cnf"] = $vimamsa_conf
67
67
  dbginfo["register"] = vma.register
68
68
  dbginfo["clipboard"] = vma.clipboard
69
69
  # dbginfo["last_event"] = $last_event
@@ -91,37 +91,29 @@ class Editor
91
91
 
92
92
  @gui.init_menu
93
93
 
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"
94
+ mkdir_if_not_exists(get_dot_path(""))
95
+ mkdir_if_not_exists(get_dot_path("backup"))
96
+ mkdir_if_not_exists(get_dot_path("testfoobar")) #TODO
97
+ listen_dir = get_dot_path("listen")
98
+ mkdir_if_not_exists(listen_dir)
98
99
  listener = Listen.to(listen_dir) do |modified, added, removed|
99
100
  debug([modified: modified, added: added, removed: removed])
100
101
  open_file_listener(added)
101
102
  end
102
103
  listener.start
103
104
 
104
- custom_fn = File.expand_path("~/.config/vimamsa/custom.rb")
105
+ custom_fn = get_dot_path("custom.rb")
105
106
  if !File.exist?(custom_fn)
106
107
  example_custom = IO.read(ppath("custom_example.rb"))
107
108
  IO.write(custom_fn, example_custom)
108
109
  end
109
110
 
110
- mkdir_if_not_exists("~/.config/vimamsa/custom.rb")
111
-
112
- $cnf[:theme] = "Twilight_edit"
113
- $cnf[:syntax_highlight] = true
114
111
  settings_path = get_dot_path("settings.rb")
115
112
  if File.exist?(settings_path)
116
- $cnf = eval(IO.read(settings_path))
113
+ # = eval(IO.read(settings_path))
114
+ #TODO
117
115
  end
118
116
 
119
- # set_gui_style(1)
120
-
121
- #TODO: remove
122
- dotfile = read_file("", "~/.config/vimamsarc")
123
- eval(dotfile) if dotfile
124
-
125
117
  custom_script = read_file("", custom_fn)
126
118
  eval(custom_script) if custom_script
127
119
 
@@ -137,18 +129,17 @@ class Editor
137
129
  require "vimamsa/langservp"
138
130
  @langsrv["ruby"] = LangSrv.new("ruby")
139
131
  @langsrv["cpp"] = LangSrv.new("cpp")
132
+ #TODO: if language enabled in config?
140
133
  end
141
134
 
142
- # build_options
143
-
144
135
  fname = nil
145
- if conf(:startup_file)
146
- fname_ = File.expand_path(conf(:startup_file))
136
+ if cnf.startup_file?
137
+ fname_ = File.expand_path(cnf.startup_file!)
147
138
  if File.exist?(fname_)
148
139
  fname = fname_
149
140
  end
150
141
  else
151
- fname = ppath("demo.txt")
142
+ # fname = ppath("demo.txt")
152
143
  end
153
144
  fname = ARGV[0] if ARGV.size >= 1 and File.file?(File.expand_path(ARGV[0]))
154
145
  # vma.add_content_search_path(Dir.pwd)
@@ -275,7 +266,7 @@ class Editor
275
266
  end
276
267
 
277
268
  def can_open_extension?(filepath)
278
- exts = $cnf[:extensions_to_open]
269
+ exts = cnf.extensions_to_open!
279
270
  extname = Pathname.new(filepath).extname.downcase
280
271
  can_open = exts.include?(extname)
281
272
  debug "CAN OPEN?: #{can_open}"
@@ -645,11 +636,16 @@ def find_project_dir_of_fn(fn)
645
636
  parent_dirs = (0..(pcomp.size - 2)).collect { |x| "/" + pcomp[0..x].join("/") }.reverse
646
637
  projdir = nil
647
638
  for pdir in parent_dirs
648
- candfn = "#{pdir}/.vma_project"
649
- if File.exist?(candfn)
650
- projdir = pdir
651
- break
639
+ candfns = []
640
+ candfns << "#{pdir}/.vma_project"
641
+ candfns << "#{pdir}/.git"
642
+ for candfn in candfns
643
+ if File.exist?(candfn)
644
+ projdir = pdir
645
+ break
646
+ end
652
647
  end
648
+ return projdir if !projdir.nil?
653
649
  end
654
650
  return projdir
655
651
  end