# module Pygments::Popen

### Public Instance Methods

alive?() click to toggle source

Check for a @pid variable, and then hit `kill -0` with the pid to check if the pid is still in the process table. If this function gives us an ENOENT or ESRCH, we can also safely return false (no process to worry about). Defensively, if EPERM is raised, in a odd/rare dying process situation (e.g., mentos is checking on the pid of a dead process and the pid has already been re-used) we'll want to raise that as a more informative Mentos exception.

Returns true if the child is alive.

    # File lib/pygments/popen.rb, line 91
    def alive?
      return true if @pid && Process.kill(0, @pid)
      false
    rescue Errno::ENOENT, Errno::ESRCH
      false
    rescue Errno::EPERM
      raise MentosError, "EPERM checking if child process is alive."
    end

css(klass='', opts={}) click to toggle source

Public: Return css for highlighted code

    # File lib/pygments/popen.rb, line 168
    def css(klass='', opts={})
      if klass.is_a?(Hash)
        opts = klass
        klass = ''
      end
      mentos(:css, ['html', klass], opts)
    end

filters() click to toggle source

Public: Return an array of all available filters

    # File lib/pygments/popen.rb, line 158
    def filters
      mentos(:get_all_filters)
    end

formatters() click to toggle source

Public: Get an array of available Pygments formatters

Returns an array of formatters.

    # File lib/pygments/popen.rb, line 103
    def formatters
      mentos(:get_all_formatters).inject(Hash.new) do | hash, (name, desc, aliases) |
        # Remove the long-winded and repetitive 'Formatter' suffix
        name.sub!(/Formatter$/, '')
        hash[name] = {
          :name => name,
          :description => desc,
          :aliases => aliases
        }
        hash
      end
    end

highlight(code, opts={}) click to toggle source

Public: Highlight code.

Takes a first-position argument of the code to be highlighted, and a second-position hash of various arguments specifiying highlighting properties.

    # File lib/pygments/popen.rb, line 198
    def highlight(code, opts={})
      # If the caller didn't give us any code, we have nothing to do,
      # so return right away.
      return code if code.nil? || code.empty?

      # Callers pass along options in the hash
      opts[:options] ||= {}

      # Default to utf-8 for the output encoding, if not given.
      opts[:options][:outencoding] ||= 'utf-8'

      # Get back the string from mentos and force encoding if we can
      str = mentos(:highlight, nil, opts, code)
      str.force_encoding(opts[:options][:outencoding]) if str.respond_to?(:force_encoding)
      str
    end

lexer_name_for(*args) click to toggle source

Public: Return the name of a lexer.

    # File lib/pygments/popen.rb, line 177
    def lexer_name_for(*args)
      # Pop off the last arg if it's a hash, which becomes our opts
      if args.last.is_a?(Hash)
        opts = args.pop
      else
        opts = {}
      end

      if args.last.is_a?(String)
        code = args.pop
      else
        code = nil
      end

      mentos(:lexer_name_for, args, opts, code)
    end

lexers() click to toggle source

Public: Get all lexers from a serialized array. This avoids needing to spawn mentos when it's not really needed (e.g,. one-off jobs, loading the Rails env, etc).

Should be preferred to lexers!

Returns an array of lexers

    # File lib/pygments/popen.rb, line 123
    def lexers
      begin
        # use upstream file path during build, use shipped file once installed
        upstream_file = File.expand_path('../../../lexers', __FILE__)
        debian_file = '/usr/share/ruby-pygments.rb/lexers'
        lexer_file = File.exists?(debian_file) ? debian_file : upstream_file
        raw = File.open(lexer_file, "rb").read
        Marshal.load(raw)
      rescue Errno::ENOENT
        raise MentosError, "Error loading lexer file. Was it created and vendored?"
      end
    end

lexers!() click to toggle source

Public: Get back all available lexers from mentos itself

Returns an array of lexers

    # File lib/pygments/popen.rb, line 139
    def lexers!
      mentos(:get_all_lexers).inject(Hash.new) do |hash, lxr|
        name = lxr[0]
        hash[name] = {
          :name => name,
          :aliases => lxr[1],
          :filenames => lxr[2],
          :mimetypes => lxr[3]
        }
        #hash["dasm16"] = {:name=>"dasm16", :aliases=>["DASM16"], :filenames=>["*.dasm16", "*.dasm"], :mimetypes=>['text/x-dasm16']}
        #hash["Puppet"] = {:name=>"Puppet", :aliases=>["puppet"], :filenames=>["*.pp"], :mimetypes=>[]}
        #hash["Augeas"] = {:name=>"Augeas", :aliases=>["augeas"], :filenames=>["*.aug"], :mimetypes=>[]}
        #hash["TOML"]   = {:name=>"TOML",   :aliases=>["toml"],   :filenames=>["*.toml"], :mimetypes=>[]}
        #hash["Slash"]  = {:name=>"Slash",  :aliases=>["slash"],  :filenames=>["*.sl"], :mimetypes=>[]}
        hash
      end
    end

start() click to toggle source

Get things started by opening a pipe to mentos (the freshmaker), a Python process that talks to the Pygments library. We'll talk back and forth across this pipe.

    # File lib/pygments/popen.rb, line 21
    def start #(pygments_path = File.expand_path('../../../vendor/pygments-main/', __FILE__))
      is_windows = RUBY_PLATFORM =~ /mswin|mingw/
      begin
        @log = Logger.new(ENV['MENTOS_LOG'] ||= is_windows ? 'NUL:' : '/dev/null')
        @log.level = Logger::INFO
        @log.datetime_format = "%Y-%m-%d %H:%M "
      rescue
        @log = Logger.new(is_windows ? 'NUL:' : '/dev/null')
      end

      # in debian we have python-pygments installed
      #ENV['PYGMENTS_PATH'] = pygments_path

      # Make sure we kill off the child when we're done
      at_exit { stop "Exiting" }

      # A pipe to the mentos python process. #popen4 gives us
      # the pid and three IO objects to write and read.
      script = "#{File.expand_path('../mentos.py', __FILE__)}"
      script = "python " + script if is_windows
      @pid, @in, @out, @err = popen4(script)
      @log.info "[#{Time.now.iso8601}] Starting pid #{@pid.to_s} with fd #{@out.to_i.to_s}."
    end

stop(reason) click to toggle source

Stop the child process by issuing a kill -9.

We then call waitpid() with the pid, which waits for that particular child and reaps it.

kill() can set errno to ESRCH if, for some reason, the file is gone; regardless the final outcome of this method will be to set our @pid variable to nil.

Technically, kill() can also fail with EPERM or EINVAL (wherein the signal isn't sent); but we have permissions, and we're not doing anything invalid here.

    # File lib/pygments/popen.rb, line 70
    def stop(reason)
      if @pid
        begin
          Process.kill('KILL', @pid)
          Process.waitpid(@pid)
        rescue Errno::ESRCH, Errno::ECHILD
        end
      end
      @log.info "[#{Time.now.iso8601}] Killing pid: #{@pid.to_s}. Reason: #{reason}"
      @pid = nil
    end

styles() click to toggle source

Public: Return an array of all available styles

    # File lib/pygments/popen.rb, line 163
    def styles
      mentos(:get_all_styles)
    end

which(command) click to toggle source

Cross platform which command from stackoverflow.com/a/5471032/284795

    # File lib/pygments/popen.rb, line 47
    def which(command)
      exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
      ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
        exts.each { |ext|
          path = File.join(dir, "#{command}#{ext}")
          return path if File.executable?(path) && !File.directory?(path)
        }
      end
      return nil
    end