Module: VER

Defined in:
lib/ver.rb,
lib/ver/font.rb,
lib/ver/help.rb,
lib/ver/mode.rb,
lib/ver/text.rb,
lib/ver/view.rb,
lib/ver/entry.rb,
lib/ver/plist.rb,
lib/ver/theme.rb,
lib/ver/keymap.rb,
lib/ver/layout.rb,
lib/ver/status.rb,
lib/ver/syntax.rb,
lib/ver/methods.rb,
lib/ver/options.rb,
lib/ver/view/list.rb,
lib/ver/text/index.rb,
lib/ver/view/entry.rb,
lib/ver/methods/help.rb,
lib/ver/methods/move.rb,
lib/ver/methods/open.rb,
lib/ver/methods/save.rb,
lib/ver/view/console.rb,
lib/ver/view/list/ex.rb,
lib/ver/methods/ctags.rb,
lib/ver/methods/views.rb,
lib/ver/methods/delete.rb,
lib/ver/methods/insert.rb,
lib/ver/methods/search.rb,
lib/ver/view/list/grep.rb,
lib/ver/methods/control.rb,
lib/ver/methods/preview.rb,
lib/ver/syntax/detector.rb,
lib/ver/view/list/theme.rb,
lib/ver/hover_completion.rb,
lib/ver/syntax/processor.rb,
lib/ver/view/list/buffer.rb,
lib/ver/view/list/syntax.rb,
lib/ver/help/describe_key.rb,
lib/ver/methods/clipboard.rb,
lib/ver/methods/shortcuts.rb,
lib/ver/view/list/methods.rb,
lib/ver/help/help_for_help.rb,
lib/ver/methods/completion.rb,
lib/ver/vendor/levenshtein.rb,
lib/ver/vendor/binary_search.rb,
lib/ver/view/list/fuzzy_file_finder.rb

Defined Under Namespace

Modules: Font, Help, Levenshtein, Methods, Optioned, Plist Classes: BinarySearch, Entry, HoverCompletion, Keymap, Layout, Mode, Options, Status, Syntax, Text, Theme, View

Constant Summary collapse

KEYSYMS =

Tk keysyms

{
  " "  => "space",
  "!"  => "exclam",
  '"'  => "quotedbl",
  "#"  => "numbersign",
  "$"  => "dollar",
  "%"  => "percent",
  "&"  => "ampersand",
  "'"  => "quoteright",
  "("  => "parenleft",
  ")"  => "parenright",
  "*"  => "asterisk",
  "+"  => "plus",
  ","  => "comma",
  "-"  => "minus",
  "."  => "period",
  "/"  => "slash",
  "0"  => "KeyPress-0",
  "1"  => "KeyPress-1",
  "2"  => "KeyPress-2",
  "3"  => "KeyPress-3",
  "4"  => "KeyPress-4",
  "5"  => "KeyPress-5",
  "6"  => "KeyPress-6",
  "7"  => "KeyPress-7",
  "8"  => "KeyPress-8",
  "9"  => "KeyPress-9",
  ":"  => "colon",
  ";"  => "semicolon",
  "<"  => "less",
  "="  => "equal",
  ">"  => "greater",
  "?"  => "question",
  "@"  => "at",
  "["  => "bracketleft",
  "\\" => "backslash",
  "]"  => "bracketright",
  "^"  => "asciicircum",
  "_"  => "underscore",
  "`"  => "quoteleft",
  "{"  => "braceleft",
  "|"  => "bar",
  "}"  => "braceright",
  "~"  => "asciitilde",
}

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.layoutObject (readonly)

Returns the value of attribute layout.



39
40
41
# File 'lib/ver.rb', line 39

def layout
  @layout
end

.optionsObject (readonly)

Returns the value of attribute options.



39
40
41
# File 'lib/ver.rb', line 39

def options
  @options
end

.pathsObject (readonly)

Returns the value of attribute paths.



39
40
41
# File 'lib/ver.rb', line 39

def paths
  @paths
end

.rootObject (readonly)

Returns the value of attribute root.



39
40
41
# File 'lib/ver.rb', line 39

def root
  @root
end

.statusObject (readonly)

Returns the value of attribute status.



39
40
41
# File 'lib/ver.rb', line 39

def status
  @status
end

Class Method Details

.emergency_bindingsObject



263
264
265
# File 'lib/ver.rb', line 263

def emergency_bindings
  Tk::Bind.bind(:all, options.emergency_exit){ exit }
end

.error(exception) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/ver.rb', line 271

def error(exception)
  @status.value = exception.message if @status
  error_tree(exception) if @root
  $stderr.puts("#{exception.class}: #{exception}", *exception.backtrace)
rescue Errno::EIO
  # The original terminal has disappeared, the $stderr pipe was closed on the
  # other side.
  [$stderr, $stdout, $stdin].each(&:close)
rescue IOError
  # Our pipes are closed, maybe put some output to a file logger here, or display
  # in a nicer way, maybe let it bubble up to Tk handling.
end

.error_tree(exception) ⇒ Object



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/ver.rb', line 284

def error_tree(exception)
  @tree ||= Tk::Tile::Treeview.new(@root)
  @tree.clear

  @tree.configure(
    columns:        %w[line method],
    displaycolumns: %w[line method]
  )
  @tree.heading('#0',     text: 'File')
  @tree.heading('line',   text: 'Line')
  @tree.heading('method', text: 'Method')
  @tree.tag_configure('error', background: '#f88')
  @tree.tag_configure('backtrace', background: '#8f8')

  context_size = 7
  frames = {}
  error_tags = ['error']
  backtrace_tags = ['backtrace']

  # from Rack::ShowExceptions
  exception.backtrace.each do |line|
    next unless line =~ /(.*?):(\d+)(:in `(.*)')?/
    filename, lineno, function = $1, $2.to_i, $4

    item = @tree.insert(nil, :end,
      text: filename, values: [lineno, function], tags: error_tags)

    begin
      lines = ::File.readlines(filename)
      _lineno = lineno - 1

      first_lineno = [_lineno - context_size, 0].max
      last_lineno  = [_lineno + context_size, lines.size].min
      context = lines[first_lineno..last_lineno]

      frames[item.id] = {
        filename: filename,
        lineno: lineno,
        function: function,
        first_lineno: first_lineno,
        last_lineno: last_lineno,
        context: context,
      }
    rescue => ex
      puts ex, ex.backtrace
    end
  end

  @tree.focus
  @tree.pack expand: true, fill: :both

  @tree.bind('<<TreeviewOpen>>'){|event|
    begin
      item = @tree.focus_item
      frame = frames[item.id]

      case frame
      when Hash
        filename, lineno, first_lineno, context =
          frame.values_at(:filename, :lineno, :first_lineno, :context)

        context.each_with_index{|line, idx|
          line_lineno = first_lineno + idx + 1
          tags = line_lineno == lineno ? error_tags : backtrace_tags
          line_item = item.insert(:end,
            text: line, values: [line_lineno], tags: tags)
          frames[line_item.id] = [filename, lineno]
        }
      when Array
        filename, lineno = frame
        @layout.views.first.find_or_create(filename, lineno){|view|
          @tree.pack_forget
        }
      end
    rescue => ex
      puts ex, ex.backtrace
    end
  }
  @tree.bind('<Escape>'){
    @tree.pack_forget
    @layout.views.first.focus
  }
end

.exitObject



208
209
210
211
212
# File 'lib/ver.rb', line 208

def exit
  Tk.exit rescue nil
  EM.stop rescue nil
  Kernel.exit
end

.find_in_loadpath(basename) ⇒ Object



227
228
229
230
231
232
233
234
# File 'lib/ver.rb', line 227

def find_in_loadpath(basename)
  loadpath.each do |dirname|
    file = dirname/basename
    return file if file.file?
  end

  nil
end

.first_startupObject



198
199
200
201
202
203
204
205
206
# File 'lib/ver.rb', line 198

def first_startup
  home, core = options.home_conf_dir, options.core_conf_dir
  home.mkpath

  (core/'rc.rb').cp(home/'rc.rb')
  (core/'scratch').cp(home/'scratch')
  (core/'tutorial').cp(home/'tutorial')
  (core/'welcome').cp(home/'welcome')
end

.load(name) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/ver.rb', line 214

def load(name)
  loadpath.each do |path|
    file = File.join(path, name)

    begin
      require(file)
      return
    rescue LoadError, TypeError => ex
      # TypeError happens on JRuby sometimes...
    end
  end
end

.loadpathObject



103
104
105
# File 'lib/ver.rb', line 103

def loadpath
  options.loadpath
end

.open_argvObject



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/ver.rb', line 236

def open_argv
  argv = ARGV.dup
  any = false

  while arg = argv.shift
    layout.create_view do |view|
      if argv.first =~ /\+\d+/
        line = argv.shift.to_i
        view.open_path(arg, line)
      else
        view.open_path(arg)
      end

      any = true
    end
  end

  any
end

.open_welcomeObject



256
257
258
259
260
261
# File 'lib/ver.rb', line 256

def open_welcome
  layout.create_view do |view|
    welcome = find_in_loadpath('welcome')
    view.open_path(welcome)
  end
end

.opened_file(text) ⇒ Object



267
268
269
# File 'lib/ver.rb', line 267

def opened_file(text)
  @paths << text.filename
end

.run(given_options = {}) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/ver.rb', line 107

def run(given_options = {})
  @options.merge!(given_options)

  setup_tk

  if Tk::RUN_EVENTLOOP_ON_MAIN_THREAD
    run_aqua
  else
    run_x11
  end
rescue => exception
  VER.error(exception)
  exit
end

.run_aquaObject



122
123
124
125
# File 'lib/ver.rb', line 122

def run_aqua
  run_core
  EM.run{ Tk.mainloop }
end

.run_coreObject



136
137
138
139
140
141
142
143
# File 'lib/ver.rb', line 136

def run_core
  first_startup unless options.home_conf_dir.directory?
  load 'rc'
  sanitize_options
  setup_widgets
  open_argv || open_welcome
  emergency_bindings
end

.run_x11Object



127
128
129
130
131
132
133
134
# File 'lib/ver.rb', line 127

def run_x11
  EM.run do
    EM.defer do
      run_core
      Tk.mainloop
    end
  end
end

.sanitize_optionsObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/ver.rb', line 163

def sanitize_options
  font = options.font

  unless font.respond_to?(:measure)
    font = Tk::Font.new(font)
    actual_hash = font.actual_hash
    options.font = Font.cache[actual_hash] = font
  end

  tabs = font.measure('0') * options.tabstop
  options.tabs = tabs

  encoding = options[:encoding]
  unless encoding.is_a?(Encoding)
    external, internal = encoding.to_s.split(':', 2)

    Encoding.default_external = Encoding.find(external) if external
    Encoding.default_internal = Encoding.find(internal) if internal
  end

  # We supply a reasonable default in case the platform doesn't have the theme
  # wished for.
  unless Tk::Tile::Style.theme_names.include?(options.tk_theme)
    options.tk_theme = 'default'
  end

  letter = /[\w\n.-]/
  space = /[^\w.-]/

  # make sure Tcl already has the vars set
  Tk.interp.eval('catch {tcl_endOfWord}')
  Tk.execute('set', 'tcl_wordchars', letter)
  Tk.execute('set', 'tcl_nonwordchars', space)
end

.setup_tkObject



145
146
147
148
# File 'lib/ver.rb', line 145

def setup_tk
  require 'ffi-tk'
  Thread.abort_on_exception = true
end

.setup_widgetsObject



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/ver.rb', line 150

def setup_widgets
  Tk::Tile.set_theme options.tk_theme

  @paths = Set.new
  @root = Tk.root
  @root.wm_geometry = '160x80'
  @layout = Layout.new(@root)
  @layout.strategy = Layout::VerticalTiling
  @status = Entry.new(@root, font: options.font)
  @status.insert :end, 'For information about VER, type F1'
  @status.pack(fill: :x)
end