Class: Rouge::Lexers::ConsoleLexer

Inherits:
Rouge::Lexer show all
Defined in:
lib/rouge/lexers/console.rb

Overview

The ConsoleLexer class is intended to lex content that represents the text that would display in a console/terminal. As distinct from the Shell lexer, ConsoleLexer will try to parse out the prompt from each line before passing the remainder of the line to the language lexer for the shell (by default, the Shell lexer).

The ConsoleLexer class accepts five options:

  1. lang: the shell language to lex (default: shell);
  2. output: the output language (default: plaintext?token=Generic.Output);
  3. prompt: comma-separated list of strings that indicate the end of a prompt (default: $,#,>,;);
  4. comments: whether to enable comments.
  5. error: comma-separated list of strings that indicate the start of an error message

The comments option, if enabled, will lex lines that begin with a # as a comment. Please note that this option will only work if the prompt is either not manually specified or, if manually specified, does not include the # character.

Most Markdown lexers that recognise GitHub-Flavored Markdown syntax, will pass the language string to Rouge as written in the original document. This allows an end user to pass options to ConsoleLexer by passing them as CGI-style parameters as in the example below.

Here's some regular text.

```console?comments=true
# This is a comment
$ cp foo bar
```

Some more regular text.

Direct Known Subclasses

IRBLexer

Constant Summary

Constants included from Token::Tokens

Token::Tokens::Num, Token::Tokens::Str

Instance Attribute Summary

Attributes inherited from Rouge::Lexer

#options

Instance Method Summary collapse

Methods inherited from Rouge::Lexer

aliases, all, #as_bool, #as_lexer, #as_list, #as_string, #as_token, #bool_option, continue_lex, #continue_lex, debug_enabled?, demo, demo_file, desc, detect?, detectable?, disable_debug!, enable_debug!, filenames, find, find_fancy, guess, guess_by_filename, guess_by_mimetype, guess_by_source, guesses, #hash_option, lex, #lex, #lexer_option, #list_option, lookup_fancy, mimetypes, option, option_docs, #reset!, #string_option, tag, #tag, title, #token_option, #with

Methods included from Token::Tokens

token

Constructor Details

#initializeConsoleLexer

Returns a new instance of ConsoleLexer.



52
53
54
55
56
57
58
59
# File 'lib/rouge/lexers/console.rb', line 52

def initialize(*)
  super
  @prompt = list_option(:prompt) { nil }
  @lang = lexer_option(:lang) { 'shell' }
  @output = lexer_option(:output) { PlainText.new(token: Generic::Output) }
  @comments = bool_option(:comments) { :guess }
  @error = list_option(:error) { nil }
end

Instance Method Details

#allow_comments?Boolean

whether to allow comments. if manually specifying a prompt that isn't simply "#", we flag this to on

Returns:

  • (Boolean)


63
64
65
66
67
68
69
70
# File 'lib/rouge/lexers/console.rb', line 63

def allow_comments?
  case @comments
  when :guess
    @prompt && !@prompt.empty? && !end_chars.include?('#')
  else
    @comments
  end
end

#comment_regexObject



72
73
74
# File 'lib/rouge/lexers/console.rb', line 72

def comment_regex
  /\A\s*?#/
end

#end_charsObject



76
77
78
79
80
81
82
83
84
# File 'lib/rouge/lexers/console.rb', line 76

def end_chars
  @end_chars ||= if @prompt.any?
    @prompt.reject { |c| c.empty? }
  elsif allow_comments?
    %w($ > ;)
  else
    %w($ # > ;)
  end
end

#error_regexObject



86
87
88
89
90
# File 'lib/rouge/lexers/console.rb', line 86

def error_regex
  @error_regex ||= if @error.any?
    /^(?:#{@error.map(&Regexp.method(:escape)).join('|')})/
  end
end

#lang_lexerObject



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rouge/lexers/console.rb', line 92

def lang_lexer
  @lang_lexer ||= case @lang
  when Lexer
    @lang
  when nil
    Shell.new(options)
  when Class
    @lang.new(options)
  when String
    Lexer.find(@lang).new(options)
  end
end

#line_regexObject



105
106
107
# File 'lib/rouge/lexers/console.rb', line 105

def line_regex
  /(\\.|[^\\])*?(\n|$)/m
end

#output_lexerObject



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rouge/lexers/console.rb', line 109

def output_lexer
  @output_lexer ||= case @output
  when nil
    PlainText.new(token: Generic::Output)
  when Lexer
    @output
  when Class
    @output.new(options)
  when String
    Lexer.find(@output).new(options)
  end
end

#process_line(input, &output) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/rouge/lexers/console.rb', line 122

def process_line(input, &output)
  input.scan(line_regex)

  # As a nicety, support the use of elisions in input text. A user can
  # write a line with only `<...>` or one or more `.` characters and
  # Rouge will treat it as a comment.
  if input[0] =~ /\A\s*(?:<[.]+>|[.]+)\s*\z/
    puts "console: matched snip #{input[0].inspect}" if @debug
    output_lexer.reset!
    lang_lexer.reset!

    yield Comment, input[0]
  elsif prompt_regex =~ input[0]
    puts "console: matched prompt #{input[0].inspect}" if @debug
    output_lexer.reset!

    yield Generic::Prompt, $&

    # make sure to take care of initial whitespace
    # before we pass to the lang lexer so it can determine where
    # the "real" beginning of the line is
    $' =~ /\A\s*/
    yield Text::Whitespace, $& unless $&.empty?

    lang_lexer.continue_lex($', &output)
  elsif comment_regex =~ input[0].strip
    puts "console: matched comment #{input[0].inspect}" if @debug
    output_lexer.reset!
    lang_lexer.reset!

    yield Comment, input[0]
  elsif error_regex =~ input[0]
    puts "console: matched error #{input[0].inspect}" if @debug
    output_lexer.reset!
    lang_lexer.reset!

    yield Generic::Error, input[0]
  else
    puts "console: matched output #{input[0].inspect}" if @debug
    lang_lexer.reset!

    output_lexer.continue_lex(input[0], &output)
  end
end

#prompt_prefix_regexObject



167
168
169
170
171
172
173
# File 'lib/rouge/lexers/console.rb', line 167

def prompt_prefix_regex
  if allow_comments?
    /[^<#]*?/m
  else
    /.*?/m
  end
end

#prompt_regexObject



175
176
177
178
179
# File 'lib/rouge/lexers/console.rb', line 175

def prompt_regex
  @prompt_regex ||= begin
    /^#{prompt_prefix_regex}(?:#{end_chars.map(&Regexp.method(:escape)).join('|')})/
  end
end

#stream_tokens(input, &output) ⇒ Object



181
182
183
184
185
186
187
# File 'lib/rouge/lexers/console.rb', line 181

def stream_tokens(input, &output)
  input = StringScanner.new(input)
  lang_lexer.reset!
  output_lexer.reset!

  process_line(input, &output) while !input.eos?
end