Class: SciteEditor

Inherits:
Object
  • Object
show all
Defined in:
lib/hilfer/scite_editor.rb

Overview

handle director interface to scite

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ SciteEditor

options can contain anything with a setter No options will create a new scite instance specifying scite_pipe_name will hook into an existing instance



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/hilfer/scite_editor.rb', line 10

def initialize( options = {} )
  # commands to scite are sent here
  @scite_pipe_name = "/tmp/hilfer.#{ENV['USER']}.#{Process.pid}.scite"

  # commands from scite arrive here
  @director_pipe_name = "/tmp/hilfer.#{ENV['USER']}.#{Process.pid}.director"
  @pipe_name_file = "/tmp/hilfer.#{ENV['USER']}.scite"

  # this is an array of objects which respond to synchronise_editor_path
  @views = []

  # the command-line options
  puts "options: #{options.inspect}" if options[:debug]
  options.each do |key,value|
    self.send( "#{key}=", value )
  end
end

Instance Attribute Details

#director_pipe_nameObject

Returns the value of attribute director_pipe_name.



33
34
35
# File 'lib/hilfer/scite_editor.rb', line 33

def director_pipe_name
  @director_pipe_name
end

#pipe_name_fileObject (readonly)

Returns the value of attribute pipe_name_file.



31
32
33
# File 'lib/hilfer/scite_editor.rb', line 31

def pipe_name_file
  @pipe_name_file
end

#scite_pidObject (readonly)

Returns the value of attribute scite_pid.



30
31
32
# File 'lib/hilfer/scite_editor.rb', line 30

def scite_pid
  @scite_pid
end

#scite_pipe_nameObject

Returns the value of attribute scite_pipe_name.



32
33
34
# File 'lib/hilfer/scite_editor.rb', line 32

def scite_pipe_name
  @scite_pipe_name
end

Instance Method Details

#activateObject

bring the SciTE instance to the current desktop and raise it.



95
96
97
# File 'lib/hilfer/scite_editor.rb', line 95

def activate
  send_cmd :focus
end

#cleanupObject



68
69
70
71
72
# File 'lib/hilfer/scite_editor.rb', line 68

def cleanup
  scite_pipe.unlink if scite_pipe.exist?
  director_pipe.unlink if director_pipe.exist?
  FileUtils.rm pipe_name_file if File.exist? pipe_name_file
end

#director_pipeObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/hilfer/scite_editor.rb', line 39

def director_pipe
  unless @director_pipe
    puts "set director pipe" if debug?
    @director_pipe = Pathname.new( director_pipe_name )

    # create the director pipe if it isn't there already
    puts "director pipe #{@director_pipe} exist?" if debug?
    unless @director_pipe.exist?
      puts "creating director pipe" if debug?
      system( "mkfifo #{@director_pipe_name}" )
    end
  end
  @director_pipe
end

#dumpObject



105
106
107
108
109
110
# File 'lib/hilfer/scite_editor.rb', line 105

def dump
  %w{dyn local user base embed}.each do |ptype|
    send_cmd 'enumproperties', ptype
  end
  #~ send_cmd 'askproperty','dyn:CurrentWord'
end

#insert(arg) ⇒ Object

insert text to editor, at current caret, or overwriting the current selection



124
125
126
127
128
129
130
131
132
# File 'lib/hilfer/scite_editor.rb', line 124

def insert( arg )
  value =
  case
    # note use of single quote - SciTE wants escaped characters
    when arg.respond_to?( :join ); arg.join( '\\n' ) + '\\n'
    else; arg.to_s
  end
  send_cmd :insert, value
end

#killObject



62
63
64
65
66
# File 'lib/hilfer/scite_editor.rb', line 62

def kill
  Process.kill 'TERM', scite_pid
  reset
  cleanup
end

#launchObject

Start up the editor if there isn’t already one. Calling it when the editor is already open does nothing. other things. Will also install a handler for SIGCHLD



158
159
160
161
162
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
197
198
199
200
201
# File 'lib/hilfer/scite_editor.rb', line 158

def launch
  return if launched?

  cleanup

  scite_cmd = "/usr/bin/scite"

  # wait for scite shutdown by SIGCHLD, and clean up fifo files.
  @handler ||= trap( "CHLD" ) do |signal|
    child_pid = Process.wait( -1, Process::WNOHANG )
    # copy this now, before something else grabs it
    process_status = $?
    if scite_pid == child_pid
      puts "process_status: #{process_status.inspect}" if debug?
      puts "cleaning pipes" if debug?
      cleanup
      reset
      puts "finished cleaning pipes" if debug?
    end
  end

  # fork and exec scite, so we can get scite's pid
  unless @scite_pid = fork
    # these seem to be deactivated by the fork, so
    # so recreate the Pathname instances
    @director_pipe = nil
    @scite_pipe = nil

    puts "in child" if debug?
    # in child, so exec scite from here, so this pid will become scite's pid
    # not passing the first arg as a 2 element array doesn't work. So
    # use the same value for the command and as argv[0]
    exec(
      [ scite_cmd ] *2,
      "-ipc.director.name=#{director_pipe}",
      "-ipc.scite.name=#{scite_pipe}"
    )
  end

  puts "in parent: scite launched with pid #{scite_pid}" if debug?

  # listen for incoming scite events, like file change and open
  start_listener
end

#launched?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/hilfer/scite_editor.rb', line 54

def launched?
  @launched || scite_pid
end

#open_action(files) ⇒ Object

open files in scite



100
101
102
103
# File 'lib/hilfer/scite_editor.rb', line 100

def open_action( files )
  files.each { |x| send_cmd "open", x.path }
  activate
end

#quitObject

shut down editor, if it’s open



118
119
120
121
# File 'lib/hilfer/scite_editor.rb', line 118

def quit
  # check for launched?, otherwise send_cmd will attempt to auto-launch.
  send_cmd :quit if launched?
end

#register_view(view) ⇒ Object

view must respond to synchronise_editor_path( fs_path )



140
141
142
# File 'lib/hilfer/scite_editor.rb', line 140

def register_view( view )
  @views << view
end

#resetObject



58
59
60
# File 'lib/hilfer/scite_editor.rb', line 58

def reset
  @scite_pid = nil
end

#responseObject

works with scite 1.x and 2.x



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/hilfer/scite_editor.rb', line 204

def response
  rv = ''
  puts "get response" if debug?
  director_pipe.open do |dpio|
    puts "checking for result" if debug?
    if IO.select( [dpio] )
      puts "reading line" if debug?
      line = dpio.read_nonblock( 4096 )
      puts "got line: #{line}" if debug?
      rv << line.gsub( /[\0\n]+$/, '' )
    end
  end
  rv
rescue EOFError
  puts "eof error" if debug?
  # just return empty
  ''
end

#scite_pipeObject



35
36
37
# File 'lib/hilfer/scite_editor.rb', line 35

def scite_pipe
  @scite_pipe ||= Pathname.new( scite_pipe_name )
end

#send_cmd(cmd, *args) ⇒ Object

send a command to SciTE



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/hilfer/scite_editor.rb', line 75

def send_cmd( cmd, *args )
  # open scite if necessary
  launch

  # make sure the pipe is open for  returns
  director_pipe

  # send the command
  scite_pipe.open('a') do |file|
    args = args.map( &:to_s) * ':'
    puts "args: #{args.inspect}" if debug?
    full = ":#{director_pipe}:#{cmd.to_s}:#{args}"
    puts "sending: #{full} to #{scite_pipe}" if debug?
    file.puts full
    puts "finished sending" if debug?
  end
end

#set_selection(fs_path) ⇒ Object

send selection to all registered views



135
136
137
# File 'lib/hilfer/scite_editor.rb', line 135

def set_selection ( fs_path )
  @views.each { |v| v.synchronise_editor_path( fs_path ) }
end

#synchronize_pathObject

fetch the current file in scite



113
114
115
# File 'lib/hilfer/scite_editor.rb', line 113

def synchronize_path
  send_cmd :askfilename
end

#unregister_view(view) ⇒ Object



144
145
146
# File 'lib/hilfer/scite_editor.rb', line 144

def unregister_view( view )
  @views.delete( view )
end

#write_pipe_nameObject



148
149
150
151
152
153
# File 'lib/hilfer/scite_editor.rb', line 148

def write_pipe_name
  File.open( pipe_name_file, 'w' ) do |f|
    f.write scite_pipe
    f.write "\n"
  end
end