Class: Pry::Editor

Inherits:
Object show all
Includes:
Helpers::CommandHelpers
Defined in:
lib/pry/editor.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::CommandHelpers

#absolute_index_number, #absolute_index_range, #get_method_or_raise, #internal_binding?, #one_index_number, #one_index_range, #one_index_range_or_number, #restrict_to_lines, #set_file_and_dir_locals, #temp_file, #unindent

Methods included from Helpers::OptionsHelpers

method_object, #method_object, method_options, #method_options

Constructor Details

#initialize(pry_instance) ⇒ Editor


27
28
29
# File 'lib/pry/editor.rb', line 27

def initialize(pry_instance)
  @pry_instance = pry_instance
end

Instance Attribute Details

#pry_instanceObject (readonly)

Returns the value of attribute pry_instance


25
26
27
# File 'lib/pry/editor.rb', line 25

def pry_instance
  @pry_instance
end

Class Method Details

.defaultObject


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/pry/editor.rb', line 7

def self.default
  if (visual = Pry::Env['VISUAL'])
    return visual
  end

  if (editor = Pry::Env['EDITOR'])
    return editor
  end

  return 'notepad' if Helpers::Platform.windows?

  %w[editor nano vi].find do |editor_exe|
    Kernel.system("which #{editor_exe} > /dev/null 2>&1")
  end
end

Instance Method Details

#blocking_flag_for_editor(blocking) ⇒ Object (private)

Some editors that run outside the terminal allow you to control whether or not to block the process from which they were launched (in this case, Pry). For those editors, return the flag that produces the desired behavior.


100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/pry/editor.rb', line 100

def blocking_flag_for_editor(blocking)
  case editor_name
  when /^emacsclient/
    '--no-wait' unless blocking
  when /^[gm]vim/
    '--nofork' if blocking
  when /^jedit/
    '-wait' if blocking
  when /^mate/, /^subl/, /^redcar/
    '-w' if blocking
  end
end

#build_editor_invocation_string(file, line, blocking) ⇒ Object

Generate the string that's used to start the editor. This includes all the flags we want as well as the file and line number we want to open at.


60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/pry/editor.rb', line 60

def build_editor_invocation_string(file, line, blocking)
  if pry_instance.config.editor.respond_to?(:call)
    args = [file, line, blocking][0...(pry_instance.config.editor.arity)]
    pry_instance.config.editor.call(*args)
  else
    sanitized_file = Helpers::Platform.windows? ? file : Shellwords.escape(file)
    editor = pry_instance.config.editor
    flag = blocking_flag_for_editor(blocking)
    start_line = start_line_syntax_for_editor(sanitized_file, line)
    "#{editor} #{flag} #{start_line}"
  end
end

#edit_tempfile_with_content(initial_content, line = 1) ⇒ Object


31
32
33
34
35
36
37
38
39
# File 'lib/pry/editor.rb', line 31

def edit_tempfile_with_content(initial_content, line = 1)
  temp_file do |f|
    f.puts(initial_content)
    f.flush
    f.close(false)
    invoke_editor(f.path, line, true)
    File.read(f.path)
  end
end

#editor_nameObject (private)

Get the name of the binary that Pry.config.editor points to.

This is useful for deciding which flags we pass to the editor as we can just use the program's name and ignore any absolute paths.

Examples:

Pry.config.editor="/home/conrad/bin/textmate -w"
editor_name
# => textmate

151
152
153
# File 'lib/pry/editor.rb', line 151

def editor_name
  File.basename(pry_instance.config.editor).split(" ").first
end

#invoke_editor(file, line, blocking = true) ⇒ Object


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/pry/editor.rb', line 41

def invoke_editor(file, line, blocking = true)
  unless pry_instance.config.editor
    raise CommandError,
          "Please set Pry.config.editor or export $VISUAL or $EDITOR"
  end

  editor_invocation = build_editor_invocation_string(file, line, blocking)
  return nil unless editor_invocation

  if Helpers::Platform.jruby?
    open_editor_on_jruby(editor_invocation)
  else
    open_editor(editor_invocation)
  end
end

#open_editor(editor_invocation) ⇒ Object (private)

Start the editor running, using the calculated invocation string


76
77
78
79
80
81
82
83
84
85
# File 'lib/pry/editor.rb', line 76

def open_editor(editor_invocation)
  # Note we dont want to use Pry.config.system here as that
  # may be invoked non-interactively (i.e via Open4), whereas we want to
  # ensure the editor is always interactive
  system(*Shellwords.split(editor_invocation)) ||
    raise(
      CommandError,
      "`#{editor_invocation}` gave exit status: #{$CHILD_STATUS.exitstatus}"
    )
end

#open_editor_on_jruby(editor_invocation) ⇒ Object (private)

We need JRuby specific code here cos just shelling out using system() appears to be pretty broken :/


89
90
91
92
93
94
95
# File 'lib/pry/editor.rb', line 89

def open_editor_on_jruby(editor_invocation)
  require 'spoon'
  pid = Spoon.spawnp(*Shellwords.split(editor_invocation))
  Process.waitpid(pid)
rescue FFI::NotFoundError
  system(editor_invocation)
end

#start_line_syntax_for_editor(file_name, line_number) ⇒ Object (private)

Return the syntax for a given editor for starting the editor and moving to a particular line within that file


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/pry/editor.rb', line 115

def start_line_syntax_for_editor(file_name, line_number)
  # special case for 1st line
  return file_name if line_number <= 1

  case editor_name
  when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/
    "+#{line_number} #{file_name}"
  when /^mate/, /^geany/
    "-l #{line_number} #{file_name}"
  when /^subl/
    "#{file_name}:#{line_number}"
  when /^uedit32/
    "#{file_name}/#{line_number}"
  when /^jedit/
    "#{file_name} +line:#{line_number}"
  when /^redcar/
    "-l#{line_number} #{file_name}"
  else
    if Helpers::Platform.windows?
      file_name.to_s
    else
      "+#{line_number} #{file_name}"
    end
  end
end