ver 2009.10.14

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.
Files changed (188) hide show
  1. data/CHANGELOG +1404 -0
  2. data/MANIFEST +187 -0
  3. data/Rakefile +30 -0
  4. data/TODO +169 -0
  5. data/bin/ver +19 -0
  6. data/config/detect.rb +109 -0
  7. data/config/keymap/vim.rb +239 -0
  8. data/config/rc.rb +0 -0
  9. data/config/scratch +3 -0
  10. data/config/syntax/ANTLR.json +275 -0
  11. data/config/syntax/ASP VB.net.json +228 -0
  12. data/config/syntax/ASP.json +135 -0
  13. data/config/syntax/ActionScript.json +168 -0
  14. data/config/syntax/Ada.json +108 -0
  15. data/config/syntax/Apache.json +342 -0
  16. data/config/syntax/AppleScript.json +721 -0
  17. data/config/syntax/Bibtex.json +253 -0
  18. data/config/syntax/Blog (HTML).json +47 -0
  19. data/config/syntax/Blog (Markdown).json +50 -0
  20. data/config/syntax/Blog (Text).json +45 -0
  21. data/config/syntax/Blog (Textile).json +45 -0
  22. data/config/syntax/Bulletin Board.json +428 -0
  23. data/config/syntax/C++.json +323 -0
  24. data/config/syntax/C.json +694 -0
  25. data/config/syntax/CSS.json +346 -0
  26. data/config/syntax/DOT.json +79 -0
  27. data/config/syntax/Diff.json +136 -0
  28. data/config/syntax/Dylan.json +104 -0
  29. data/config/syntax/Eiffel.json +128 -0
  30. data/config/syntax/Erlang.json +1636 -0
  31. data/config/syntax/F-Script.json +137 -0
  32. data/config/syntax/FXScript.json +260 -0
  33. data/config/syntax/Gri.json +141 -0
  34. data/config/syntax/HTML (Mason).json +207 -0
  35. data/config/syntax/HTML (Rails).json +52 -0
  36. data/config/syntax/HTML (Tcl).json +42 -0
  37. data/config/syntax/HTML for ASP.net.json +736 -0
  38. data/config/syntax/HTML-ASP.json +45 -0
  39. data/config/syntax/HTML.json +614 -0
  40. data/config/syntax/Haskell.json +407 -0
  41. data/config/syntax/Inform.json +80 -0
  42. data/config/syntax/Ini.json +91 -0
  43. data/config/syntax/Io.json +142 -0
  44. data/config/syntax/Java.json +745 -0
  45. data/config/syntax/JavaProperties.json +42 -0
  46. data/config/syntax/JavaScript.json +446 -0
  47. data/config/syntax/LaTeX Beamer.json +65 -0
  48. data/config/syntax/LaTeX Log.json +88 -0
  49. data/config/syntax/LaTeX.json +962 -0
  50. data/config/syntax/Lighttpd.json +93 -0
  51. data/config/syntax/Lisp.json +101 -0
  52. data/config/syntax/Literate Haskell.json +55 -0
  53. data/config/syntax/Logtalk.json +289 -0
  54. data/config/syntax/Lua.json +146 -0
  55. data/config/syntax/M.json +744 -0
  56. data/config/syntax/MEL.json +161 -0
  57. data/config/syntax/MIPS.json +114 -0
  58. data/config/syntax/Mail.json +224 -0
  59. data/config/syntax/Makefile.json +66 -0
  60. data/config/syntax/Markdown.json +644 -0
  61. data/config/syntax/Modula-3.json +80 -0
  62. data/config/syntax/Movable Type.json +348 -0
  63. data/config/syntax/OCaml.json +1391 -0
  64. data/config/syntax/Objective-C++.json +21 -0
  65. data/config/syntax/OpenGL.json +24 -0
  66. data/config/syntax/PHP.json +2184 -0
  67. data/config/syntax/Pascal.json +128 -0
  68. data/config/syntax/Perl.json +2091 -0
  69. data/config/syntax/Plain text.json +49 -0
  70. data/config/syntax/Processing.json +188 -0
  71. data/config/syntax/Quake3 Config.json +54 -0
  72. data/config/syntax/R.json +157 -0
  73. data/config/syntax/Rez.json +137 -0
  74. data/config/syntax/Ruby on Rails.json +170 -0
  75. data/config/syntax/Ruby.json +1753 -0
  76. data/config/syntax/SQL (Rails).json +31 -0
  77. data/config/syntax/SQL.json +435 -0
  78. data/config/syntax/SWIG.json +96 -0
  79. data/config/syntax/Scheme.json +359 -0
  80. data/config/syntax/Shell-Unix-Generic.json +1198 -0
  81. data/config/syntax/Slate.json +265 -0
  82. data/config/syntax/Smarty.json +110 -0
  83. data/config/syntax/Standard ML.json +322 -0
  84. data/config/syntax/Subversion commit message.json +62 -0
  85. data/config/syntax/Tcl.json +278 -0
  86. data/config/syntax/TeX Math.json +83 -0
  87. data/config/syntax/TeX.json +157 -0
  88. data/config/syntax/Textile.json +273 -0
  89. data/config/syntax/Twiki.json +436 -0
  90. data/config/syntax/Vectorscript.json +97 -0
  91. data/config/syntax/XML strict.json +148 -0
  92. data/config/syntax/XML.json +301 -0
  93. data/config/syntax/XSL.json +96 -0
  94. data/config/syntax/YAML.json +293 -0
  95. data/config/syntax/iCalendar.json +51 -0
  96. data/config/syntax/reStructuredText.json +403 -0
  97. data/config/theme/Active4D.json +260 -0
  98. data/config/theme/All Hallow's Eve.json +171 -0
  99. data/config/theme/Amy.json +359 -0
  100. data/config/theme/BBEdit.json +269 -0
  101. data/config/theme/Bespin.json +322 -0
  102. data/config/theme/Blackboard.json +215 -0
  103. data/config/theme/BoysAndGirls01.json +156 -0
  104. data/config/theme/Brilliance Black.json +1695 -0
  105. data/config/theme/Brilliance Dull.json +1451 -0
  106. data/config/theme/Classic Modified.json +288 -0
  107. data/config/theme/Cobalt.json +345 -0
  108. data/config/theme/Cool Glow.json +215 -0
  109. data/config/theme/Dawn.json +258 -0
  110. data/config/theme/Eiffel.json +270 -0
  111. data/config/theme/Espresso Libre.json +247 -0
  112. data/config/theme/Fluidvision.json +272 -0
  113. data/config/theme/IDLE.json +159 -0
  114. data/config/theme/LAZY.json +178 -0
  115. data/config/theme/Mac Classic.json +277 -0
  116. data/config/theme/MagicWB (Amiga).json +231 -0
  117. data/config/theme/Merbivore Soft.json +181 -0
  118. data/config/theme/Merbivore.json +181 -0
  119. data/config/theme/Monokai.json +177 -0
  120. data/config/theme/Notepad2.json +166 -0
  121. data/config/theme/Pastels on Dark.json +437 -0
  122. data/config/theme/RubyBlue.json +226 -0
  123. data/config/theme/Sin City 2.json +361 -0
  124. data/config/theme/Slate.json +270 -0
  125. data/config/theme/Slush & Poppies.json +232 -0
  126. data/config/theme/SpaceCadet.json +143 -0
  127. data/config/theme/Sunburst.json +415 -0
  128. data/config/theme/Twilight BG FG.json +633 -0
  129. data/config/theme/Twilight.json +321 -0
  130. data/config/theme/Whys Poignant.json +119 -0
  131. data/config/theme/Zenburnesque.json +237 -0
  132. data/config/theme/barf.json +155 -0
  133. data/config/theme/fake.json +418 -0
  134. data/config/theme/happydeluxe.json +114 -0
  135. data/config/theme/iLife 05.json +393 -0
  136. data/config/theme/iPlastic.json +177 -0
  137. data/config/theme/mintBlue Dark.json +414 -0
  138. data/config/theme/mintBlue.json +415 -0
  139. data/config/theme/monoindustrial.json +276 -0
  140. data/config/theme/starlight.json +67 -0
  141. data/config/tutorial +74 -0
  142. data/config/welcome +115 -0
  143. data/help/index.verh +14 -0
  144. data/lib/ver.rb +156 -0
  145. data/lib/ver/entry.rb +97 -0
  146. data/lib/ver/keymap.rb +96 -0
  147. data/lib/ver/layout.rb +107 -0
  148. data/lib/ver/methods.rb +19 -0
  149. data/lib/ver/methods/completion.rb +116 -0
  150. data/lib/ver/methods/control.rb +340 -0
  151. data/lib/ver/methods/insert.rb +6 -0
  152. data/lib/ver/methods/move.rb +65 -0
  153. data/lib/ver/methods/search.rb +33 -0
  154. data/lib/ver/methods/select.rb +145 -0
  155. data/lib/ver/methods/views.rb +21 -0
  156. data/lib/ver/mode.rb +160 -0
  157. data/lib/ver/options.rb +207 -0
  158. data/lib/ver/plist.rb +106 -0
  159. data/lib/ver/status.rb +67 -0
  160. data/lib/ver/syntax.rb +68 -0
  161. data/lib/ver/syntax/detector.rb +53 -0
  162. data/lib/ver/syntax/processor.rb +48 -0
  163. data/lib/ver/text.rb +374 -0
  164. data/lib/ver/textpow.rb +357 -0
  165. data/lib/ver/theme.rb +162 -0
  166. data/lib/ver/vendor/fuzzy_file_finder.rb +340 -0
  167. data/lib/ver/view.rb +163 -0
  168. data/lib/ver/view/entry.rb +28 -0
  169. data/lib/ver/view/list.rb +137 -0
  170. data/lib/ver/view/list/buffer.rb +27 -0
  171. data/lib/ver/view/list/fuzzy_file_finder.rb +44 -0
  172. data/lib/ver/view/list/syntax.rb +13 -0
  173. data/lib/ver/view/list/theme.rb +13 -0
  174. data/spec/keymap.rb +224 -0
  175. data/tasks/bacon.rake +49 -0
  176. data/tasks/changelog.rake +18 -0
  177. data/tasks/gem.rake +22 -0
  178. data/tasks/gem_installer.rake +76 -0
  179. data/tasks/grancher.rake +12 -0
  180. data/tasks/install_dependencies.rake +6 -0
  181. data/tasks/manifest.rake +4 -0
  182. data/tasks/plist2json.rake +35 -0
  183. data/tasks/rcov.rake +18 -0
  184. data/tasks/release.rake +12 -0
  185. data/tasks/reversion.rake +8 -0
  186. data/tasks/syntax_list.rake +31 -0
  187. data/ver.gemspec +29 -0
  188. metadata +241 -0
data/lib/ver/keymap.rb ADDED
@@ -0,0 +1,96 @@
1
+ module VER
2
+ class Keymap
3
+ def self.get(options)
4
+ name = options.fetch(:name)
5
+
6
+ find_and_load(name)
7
+ send(name, options)
8
+ end
9
+
10
+ def self.find(keymap_name)
11
+ VER.find_in_loadpath("keymap/#{keymap_name}.rb")
12
+ end
13
+
14
+ def self.find_and_load(keymap_name)
15
+ if path = find(keymap_name)
16
+ sane = path.dirname/path.basename(path.extname)
17
+ require sane.to_s
18
+ else
19
+ raise LoadError, "cannot find keymap: %p" % [keymap_name]
20
+ end
21
+ end
22
+
23
+ attr_accessor :modes, :callback, :widget, :tag
24
+ attr_reader :mode
25
+
26
+ def initialize(options)
27
+ @callback = options.fetch(:receiver)
28
+ @widget = options.fetch(:widget, @callback)
29
+ @modes = {}
30
+
31
+ prepare_tag
32
+ prepare_default_binds
33
+ end
34
+
35
+ def send(*args)
36
+ @callback.__send__(*args)
37
+ end
38
+
39
+ def enter_key(key)
40
+ modes[mode].enter_key key
41
+ end
42
+
43
+ def enter_missing(key)
44
+ modes[mode].enter_missing key
45
+ end
46
+
47
+ def prepare_tag
48
+ self.tag = TkBindTag.new
49
+ tags = widget.bindtags
50
+
51
+ index = tags.index{|element| element.is_a?(Class) }
52
+ tags[index - 1, 0] = @tag
53
+
54
+ widget.bindtags = tags
55
+ end
56
+
57
+ def prepare_default_binds
58
+ tag.bind 'Key' do |event|
59
+ case event.char
60
+ when ''
61
+ # enter_missing event.keysym
62
+ # p event
63
+ else
64
+ enter_missing event.char
65
+ end
66
+
67
+ Tk.callback_break
68
+ end
69
+
70
+ 0.upto 9 do |n|
71
+ tag.bind("KeyPress-#{n}") do |key|
72
+ enter_key n.to_s
73
+ Tk.callback_break
74
+ end
75
+ end
76
+ end
77
+
78
+ def register(key)
79
+ tag.bind(key){|event|
80
+ enter_key key
81
+ Tk.callback_break
82
+ }
83
+ end
84
+
85
+ # TODO: callbacks
86
+ def mode=(cm)
87
+ @mode = cm.to_sym
88
+ end
89
+
90
+ def add_mode(name)
91
+ @modes[name.to_sym] = mode = VER::Mode.new(name, self)
92
+ yield mode if block_given?
93
+ mode
94
+ end
95
+ end
96
+ end
data/lib/ver/layout.rb ADDED
@@ -0,0 +1,107 @@
1
+ module VER
2
+ class Layout < Ttk::Frame
3
+ attr_reader :strategy, :views
4
+
5
+ def initialize(parent, options = {})
6
+ super
7
+
8
+ pack(fill: :both, expand: true)
9
+
10
+ @views = []
11
+ self.strategy = Layout::VerticalTiling
12
+ end
13
+
14
+ def strategy=(mod)
15
+ @strategy = mod
16
+ apply if @views.any?
17
+ end
18
+
19
+ def create_view
20
+ view = View.new(self)
21
+ yield view
22
+ @views << view
23
+
24
+ apply
25
+ end
26
+
27
+ def close_view(view)
28
+ @views.delete view
29
+ view.destroy
30
+
31
+ if previous = @views.last
32
+ apply
33
+ previous.focus
34
+ else
35
+ Tk.exit
36
+ end
37
+ end
38
+
39
+ def focus_next(current)
40
+ return unless index = @views.index(current)
41
+
42
+ found = @views[index + 1] || @views[0]
43
+ found.focus
44
+ end
45
+
46
+ def focus_prev(current)
47
+ return unless index = @views.index(current)
48
+
49
+ found = @views[index - 1]
50
+ found.focus
51
+ end
52
+
53
+ def apply(options = {})
54
+ strategy.apply(self, options)
55
+ end
56
+
57
+ module VerticalTiling
58
+ DEFAULT = { left: 1, right: -1 }
59
+
60
+ module_function
61
+
62
+ def apply(layout, options = {})
63
+ slaves = layout.winfo_children
64
+ left, right = DEFAULT.merge(options).values_at(:left, :right)
65
+ head, tail = slaves[0...left], slaves[left..right]
66
+ width = tail.size == 0 ? 1.0 : 0.5
67
+ head_step = 1.0 / head.size
68
+ tail_step = 1.0 / tail.size
69
+
70
+ head.each_with_index do |slave, idx|
71
+ slave.place(relx: 0.0, rely: (head_step * idx),
72
+ relheight: head_step, relwidth: width)
73
+ end
74
+
75
+ tail.each_with_index do |slave, idx|
76
+ slave.place(relx: 0.5, rely: (tail_step * idx),
77
+ relheight: tail_step, relwidth: width)
78
+ end
79
+ end
80
+ end
81
+
82
+ module HorizontalTiling
83
+ DEFAULT = { top: 1, bottom: -1 }
84
+
85
+ module_function
86
+
87
+ def apply(layout, options = {})
88
+ slaves = layout.winfo_children
89
+ top, bottom = DEFAULT.merge(options).values_at(:top, :bottom)
90
+ head, tail = slaves[0...top], slaves[top..bottom]
91
+ height = tail.size == 0 ? 1.0 : 0.5
92
+ head_step = 1.0 / head.size
93
+ tail_step = 1.0 / tail.size
94
+
95
+ head.each_with_index do |slave, idx|
96
+ slave.place(relx: (head_step * idx), rely: 0.0,
97
+ relheight: height, relwidth: head_step)
98
+ end
99
+
100
+ tail.each_with_index do |slave, idx|
101
+ slave.place(relx: (tail_step * idx), rely: 0.5,
102
+ relheight: height, relwidth: tail_step)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,19 @@
1
+ require 'ver/methods/move'
2
+ require 'ver/methods/views'
3
+ require 'ver/methods/insert'
4
+ require 'ver/methods/control'
5
+ require 'ver/methods/search'
6
+ require 'ver/methods/select'
7
+ require 'ver/methods/completion'
8
+
9
+ module VER
10
+ module Methods
11
+ include Move
12
+ include Views
13
+ include Insert
14
+ include Control
15
+ include Search
16
+ include Select
17
+ include Completion
18
+ end
19
+ end
@@ -0,0 +1,116 @@
1
+ module VER
2
+ module Methods
3
+ module Completion
4
+ def complete_file
5
+ files = file_completions
6
+ complete(files)
7
+ end
8
+
9
+ def complete_aspell
10
+ words = aspell_completions
11
+ complete(words)
12
+ end
13
+
14
+ def file_completions
15
+ word = get('insert wordstart', 'insert wordend')
16
+
17
+ glob = "#{word}*{**/*,/**/*}"
18
+ p glob
19
+ Dir[glob].uniq
20
+ end
21
+
22
+ def aspell_completions
23
+ word = get('insert wordstart', 'insert wordend')
24
+
25
+ if result = aspell_execute(word)[word]
26
+ result[:suggestions]
27
+ else
28
+ [word]
29
+ end
30
+ end
31
+
32
+ ASPELL_PARSE = /^& (.*?) (\d+) (\d+): (.*)$/
33
+
34
+ def aspell_execute(word)
35
+ require 'open3'
36
+ results = {}
37
+
38
+ Open3.popen3("aspell pipe") do |stdin, stdout, stderr|
39
+ stdin.print("^#{word}")
40
+ stdin.close
41
+ result = stdout.read
42
+
43
+ result.scan(ASPELL_PARSE) do |original, count, offset, suggestions|
44
+ results[original] = {
45
+ count: count.to_i,
46
+ offset: offset.to_i,
47
+ suggestions: suggestions.split(/\s*,\s*/),
48
+ }
49
+ end
50
+ end
51
+
52
+ return results
53
+ end
54
+
55
+ def complete(words)
56
+ return if words.empty?
57
+
58
+ x, y = caret.values_at('x', 'y')
59
+ longest_word = words.map{|word| word.size }.max
60
+
61
+ list = Tk::Listbox.new(self){
62
+ borderwidth 0
63
+ width longest_word + 2
64
+ height words.size
65
+ place x: x, y: y
66
+ focus
67
+ }
68
+
69
+ list.value = words
70
+ list.selection_set 0
71
+
72
+ # go down
73
+ list.bind('j'){|event|
74
+ index = list.curselection.first + 1
75
+ max = list.size
76
+
77
+ if index < max
78
+ list.selection_clear(0, 'end')
79
+ list.selection_set(index)
80
+ list.activate(index)
81
+ end
82
+
83
+ Tk.callback_break
84
+ }
85
+
86
+ # go up
87
+ list.bind('k'){|event|
88
+ index = list.curselection.first - 1
89
+
90
+ if index >= 0
91
+ list.selection_clear(0, 'end')
92
+ list.selection_set(index)
93
+ list.activate(index)
94
+ end
95
+
96
+ Tk.callback_break
97
+ }
98
+
99
+ list.bind('Return'){|event|
100
+ index = list.curselection.first
101
+ replacement = list.get(index)
102
+ replace('insert wordstart', 'insert wordend', replacement)
103
+ focus
104
+ list.destroy
105
+ Tk.callback_break
106
+ }
107
+
108
+ list.bind('Escape'){|event|
109
+ focus
110
+ list.destroy
111
+ Tk.callback_break
112
+ }
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,340 @@
1
+ module VER
2
+ module Methods
3
+ module Control
4
+ def status_theme_select
5
+ return unless @syntax
6
+
7
+ status_ask 'Theme name: ' do |name|
8
+ load_theme(name) || "No theme called #{name} found"
9
+ end
10
+ end
11
+
12
+ def theme_switch
13
+ return unless @syntax
14
+
15
+ View::List::Theme.new(self){|name| load_theme(name) }
16
+ end
17
+
18
+ def syntax_switch
19
+ return unless @syntax
20
+
21
+ View::List::Syntax.new(self){|name| load_syntax(name) }
22
+ end
23
+
24
+ def status_evaluate
25
+ status_ask 'Eval expression: ' do |term|
26
+ eval(term)
27
+ end
28
+ end
29
+
30
+ def status_ask(prompt, &callback)
31
+ @status.ask(prompt){|*args|
32
+ begin
33
+ callback.call(*args)
34
+ rescue => ex
35
+ p ex
36
+ status.message ex.message
37
+ ensure
38
+ focus
39
+ end
40
+ }
41
+ end
42
+
43
+ def smart_evaluate
44
+ from, to = tag_ranges(:sel).first
45
+
46
+ if from && to
47
+ selection_evaluate
48
+ else
49
+ line_evaluate
50
+ end
51
+ end
52
+
53
+ def line_evaluate
54
+ text = get('insert linestart', 'insert lineend')
55
+ result = eval(text)
56
+ insert("insert lineend", "\n#{result.inspect}\n")
57
+ end
58
+
59
+ def buffer_switch
60
+ View::List::Buffer.new self do |file|
61
+
62
+ # VER.resume_buffer file_path
63
+ open_path file if File.exists? file
64
+ end
65
+ end
66
+
67
+ def window_switch(count = nil)
68
+ if count
69
+ p count: count
70
+ else
71
+ View::List::Window.new self do |view|
72
+ view.focus
73
+ # open_path(path)
74
+ end
75
+ end
76
+ end
77
+
78
+ def file_save
79
+ save_to(filename)
80
+ end
81
+
82
+ def file_save_popup
83
+ filetypes = [
84
+ ['ALL Files', '*' ],
85
+ ['Text Files', '*.txt'],
86
+ ]
87
+
88
+ filename = ::File.basename @filename
89
+ extension = ::File.extname @filename
90
+ directory = ::File.dirname @filename
91
+
92
+ fpath = Tk.getSaveFile(
93
+ initialfile: filename,
94
+ initialdir: directory,
95
+ defaultextension: extension,
96
+ filetypes: filetypes
97
+ )
98
+
99
+ return if fpath.empty?
100
+
101
+ save_to(fpath)
102
+ end
103
+
104
+ # Some strategies are discussed at:
105
+ #
106
+ # http://bitworking.org/news/390/text-editor-saving-routines
107
+ #
108
+ # I try another, "wasteful" approach, copying the original file to a
109
+ # temporary location, overwriting the contents in the copy, then moving the
110
+ # file to the location of the original file.
111
+ #
112
+ # This way all permissions should be kept identical without any effort, but
113
+ # it will take up additional disk space.
114
+ #
115
+ # If there is some failure during the normal saving procedure, we will
116
+ # simply overwrite the original file in place, make sure you have good insurance ;)
117
+ def save_to(to)
118
+ save_smart(filename, to)
119
+ rescue => ex
120
+ puts "#{ex.class}: #{ex}", *ex.backtrace
121
+ save_dumb(filename, to)
122
+ end
123
+
124
+ def save_smart(from, to)
125
+ sha1 = Digest::SHA1.hexdigest([from, to].join)
126
+ temp_path = File.join(Dir.tmpdir, 'ver', sha1)
127
+ temp_dir = File.dirname(temp_path)
128
+
129
+ FileUtils.mkdir_p(temp_dir)
130
+ FileUtils.copy_file(from, temp_path, preserve = true)
131
+ File.open(temp_path, 'w+') do |io|
132
+ io.write(self.value)
133
+ end
134
+ FileUtils.mv(temp_path, to)
135
+
136
+ status.message "Saved to #{to}"
137
+ rescue Errno::ENOENT
138
+ save_dumb(to)
139
+ end
140
+
141
+ def save_dumb(to)
142
+ File.open(to, 'w+') do |io|
143
+ io.write(self.value)
144
+ end
145
+
146
+ status.message "Saved to #{to}"
147
+ end
148
+
149
+ def file_open_popup
150
+ filetypes = [
151
+ ['ALL Files', '*' ],
152
+ ['Text Files', '*.txt'],
153
+ ]
154
+
155
+ fpath = Tk.getOpenFile(filetypes: filetypes)
156
+
157
+ return if fpath.empty?
158
+
159
+ open_path(fpath)
160
+ end
161
+
162
+ def file_open_fuzzy
163
+ View::List::FuzzyFileFinder.new self do |path|
164
+ open_path(path)
165
+ end
166
+ end
167
+
168
+ def delete_char_left
169
+ delete 'insert - 1 char'
170
+ end
171
+
172
+ def delete_char_right
173
+ delete 'insert'
174
+ end
175
+
176
+ def delete_word_right
177
+ delete 'insert', 'insert wordend'
178
+ end
179
+
180
+ def delete_word_left
181
+ delete 'insert wordstart', 'insert'
182
+ end
183
+
184
+ def delete_line
185
+ delete 'insert linestart', 'insert lineend + 1 char'
186
+ end
187
+
188
+ def delete_to_eol
189
+ delete 'insert', 'insert lineend'
190
+ end
191
+
192
+ def delete_to_eol_then_insert
193
+ delete_to_eol
194
+ start_insert_mode
195
+ end
196
+
197
+ def join_lines
198
+ start_of_next_line = search(/\S/, 'insert lineend')
199
+ replace('insert lineend', start_of_next_line, ' ')
200
+ rescue RuntimeError => exception
201
+ return if exception.message =~ /Index "\d+\.\d+" before "insert lineend" in the text/
202
+ raise exception
203
+ end
204
+
205
+ def insert_string(string)
206
+ # puts "Insert %p in mode %p" % [string, keymap.mode]
207
+ insert :insert, string unless string.empty?
208
+ end
209
+
210
+ def ignore_string(string)
211
+ status.message "Ignore %p in mode %p" % [string, keymap.mode]
212
+ end
213
+
214
+ def replace_char
215
+ status_ask 'Replace with: ' do |string|
216
+ replace('insert', 'insert + 1 chars', string)
217
+ end
218
+ end
219
+
220
+ def indent_line
221
+ insert('insert linestart', ' ')
222
+ end
223
+
224
+ def unindent_line
225
+ line = get('insert linestart', 'insert lineend')
226
+
227
+ return unless line =~ /^(\s\s?)/
228
+
229
+ replace(
230
+ 'insert linestart',
231
+ "insert linestart + #{$1.size} chars",
232
+ ''
233
+ )
234
+ end
235
+
236
+ def insert_indented_newline_below
237
+ line = get('insert linestart', 'insert lineend')
238
+
239
+ indent = line.empty? ? "" : (line[/^\s+/] || '')
240
+ mark_set :insert, 'insert lineend'
241
+ insert :insert, "\n#{indent}"
242
+
243
+ start_insert_mode
244
+ end
245
+
246
+ def insert_indented_newline_above
247
+ y, x = index(:insert).split('.').map(&:to_i)
248
+
249
+ if y > 1
250
+ go_line_up
251
+ insert_indented_newline_below
252
+ else
253
+ insert('insert linestart', "\n")
254
+ mark_set(:insert, 'insert - 1 line')
255
+ end
256
+ end
257
+
258
+ def insert_newline
259
+ insert :insert, "\n"
260
+ end
261
+
262
+ def insert_indented_newline
263
+ line1 = get('insert linestart', 'insert lineend')
264
+ indentation1 = line1[/^\s+/] || ''
265
+ insert :insert, "\n"
266
+
267
+ line2 = get('insert linestart', 'insert lineend')
268
+ indentation2 = line2[/^\s+/] || ''
269
+
270
+ replace(
271
+ 'insert linestart',
272
+ "insert linestart + #{indentation2.size} chars",
273
+ indentation1
274
+ )
275
+ end
276
+
277
+ def insert_tab
278
+ insert :insert, "\t"
279
+ end
280
+
281
+ def eol_then_insert_mode
282
+ go_end_of_line
283
+ start_insert_mode
284
+ end
285
+
286
+ def sol_then_insert_mode
287
+ go_beginning_of_line
288
+ start_insert_mode
289
+ end
290
+
291
+ def start_insert_mode
292
+ self.mode = :insert
293
+ end
294
+
295
+ def start_control_mode
296
+ self.mode = :control
297
+ end
298
+
299
+ def copy_line
300
+ copy get('insert linestart', 'insert lineend + 1 chars')
301
+ end
302
+
303
+ def copy_right_word
304
+ copy get('insert', 'insert wordend')
305
+ end
306
+
307
+ def copy_left_word
308
+ copy get('insert', 'insert wordstart')
309
+ end
310
+
311
+ # FIXME: nasty hack or neccesary?
312
+ def paste
313
+ text = TkClipboard.get
314
+ paste_continous text
315
+
316
+ rescue RuntimeError => ex
317
+ if ex.message =~ /form "STRING" not defined/
318
+ array = TkClipboard.get type: Array
319
+ paste_tk_array array
320
+ else
321
+ Kernel.raise ex
322
+ end
323
+ end
324
+
325
+ def undo
326
+ edit_undo
327
+ touch!
328
+ rescue RuntimeError => ex
329
+ status.value = ex.message
330
+ end
331
+
332
+ def redo
333
+ edit_redo
334
+ touch!
335
+ rescue RuntimeError => ex
336
+ status.value = ex.message
337
+ end
338
+ end
339
+ end
340
+ end