class CODE_HIGHLIGHTING_TRANSFORMER
Code highlighting transformer
note
description: "Code highlighting transformer"
author: "Finnian Reilly"
copyright: "Copyright (c) 2001-2017 Finnian Reilly"
contact: "finnian at eiffel hyphen loop dot com"
license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
date: "2021-01-10 12:58:40 GMT (Sunday 10th January 2021)"
revision: "9"
class
CODE_HIGHLIGHTING_TRANSFORMER
inherit
EL_FILE_PARSER_TEXT_EDITOR
redefine
make_default, on_unmatched_text, new_output
end
EL_PLAIN_TEXT_LINE_STATE_MACHINE
rename
make as make_machine
end
EL_EIFFEL_TEXT_PATTERN_FACTORY
EL_EIFFEL_CONSTANTS
EL_EIFFEL_KEYWORDS
EL_MODULE_XML
create
make, make_from_file
feature {NONE} -- Initialization
make_default
do
make_machine
Precursor
end
make (a_output: like output)
--
do
make_default
output := a_output
set_encoding_from_other (output)
end
make_from_file (a_output: like output; a_file_path: EL_FILE_PATH; a_selected_features: like selected_features)
--
do
make (a_output)
file_path := a_file_path
selected_features := a_selected_features
if attached open_lines (file_path, Utf_8) as source_lines then
create selected_text.make (source_lines.byte_count)
if selected_features.is_empty then
do_once_with_file_lines (agent find_class_declaration, source_lines)
else
do_once_with_file_lines (agent find_feature_block, source_lines)
end
end
set_source_text (selected_text)
end
feature {NONE} -- Pattern definitions
delimiting_pattern: like one_of
--
local
double_angle_brackets: like one_of
do
double_angle_brackets := one_of (<<
string_literal ("<<"),
string_literal (">>")
>>)
create Result.make (<<
comment |to| agent put_emphasis (?, "comment"),
unescaped_manifest_string (Default_action) |to| agent put_emphasis (?, "quote"),
quoted_manifest_string (Default_action) |to| agent put_emphasis (?, "quote"),
character_manifest (Default_action) |to| agent put_emphasis (?, "quote"),
double_angle_brackets |to| agent put_emphasis (?, "class"),
identifier |to| agent on_identifier
>>)
end
feature {NONE} -- Parsing actions
on_unmatched_text (text: EL_STRING_VIEW)
--
do
put_escaped (text)
end
on_identifier (text: EL_STRING_VIEW)
--
local
i: INTEGER
has_lower: BOOLEAN
word: STRING
do
word := text
from i := 1 until has_lower or i > word.count loop
has_lower := word.item (i).to_character_8.is_lower
i := i + 1
end
if has_lower then
if Reserved_word_set.has (word) then
put_emphasis (text, "keyword")
else
put_escaped (text)
end
elseif word.count > 1 and word /~ "NONE" then
put_emphasis (text, Keyword_class)
else
put_escaped (text)
end
end
feature {NONE} -- Line procedure transitions for whole class
find_class_declaration (line: ZSTRING)
--
do
if line.starts_with (Keyword_class) or else line.starts_with (Keyword_deferred) then
append_to_selected_text (line)
state := agent append_to_selected_text
end
end
append_to_selected_text (line: ZSTRING)
--
do
if not selected_text.is_empty then
selected_text.append_character ('%N')
end
line.grow (line.count + line.occurrences ('%T') * (Tab_spaces.count - 1))
line.replace_substring_all (Tab_character_string, Tab_spaces)
selected_text.append (line)
end
feature {NONE} -- Line procedure transitions for selected features
find_feature_block (line: ZSTRING)
--
do
if line.starts_with (Keyword_feature) then
last_feature_block_line := line
state := agent find_selected_feature
end
end
find_selected_feature (line: ZSTRING)
--
local
trimmed_line: ZSTRING
tab_count: INTEGER
found: BOOLEAN
do
if line.starts_with (Keyword_feature) then
last_feature_block_line := line
else
create trimmed_line.make_from_other (line)
trimmed_line.left_adjust
tab_count := line.count - trimmed_line.count
from selected_features.start until found or selected_features.after loop
if tab_count = 1
and then
trimmed_line.starts_with (selected_features.item)
and then
(trimmed_line.count > selected_features.item.count
implies not trimmed_line.item (selected_features.item.count + 1).is_alpha_numeric)
then
found := True
if last_feature_block_line /= last_feature_block_line_appended then
append_to_selected_text (last_feature_block_line)
selected_text.append_character ('%N')
last_feature_block_line_appended := last_feature_block_line
end
append_to_selected_text (line)
state := agent find_feature_end
end
selected_features.forth
end
end
end
find_feature_end (line: ZSTRING)
--
local
trimmed_line: ZSTRING
tab_count: INTEGER
do
create trimmed_line.make_from_other (line)
trimmed_line.left_adjust
tab_count := line.count - trimmed_line.count
if tab_count = 1 then
state := agent find_selected_feature
find_selected_feature (line)
else
append_to_selected_text (line)
end
end
feature {NONE} -- Implementation
put_emphasis (text: EL_STRING_VIEW; name: STRING)
--
do
put_string ("<em id=%""); put_string (name); put_string ("%">")
put_escaped (text)
put_string (End_emphasis)
end
put_escaped (text: EL_STRING_VIEW)
--
do
put_string (XML.escaped_128_plus (text.to_string_8))
end
new_output: EL_PLAIN_TEXT_FILE
-- Use the initialized output
do
Result := output
end
selected_text: ZSTRING
selected_features: LIST [ZSTRING]
last_feature_block_line: ZSTRING
last_feature_block_line_appended: ZSTRING
feature {NONE} -- Constants
End_emphasis: ZSTRING
once
Result := "</em>"
end
Tab_spaces: ZSTRING
--
once
create Result.make_filled (' ', 4)
end
Tab_character_string: ZSTRING
once
Result := "%T"
end
Reserved_word_set: EL_HASH_SET [ZSTRING]
--
once
create Result.make (Reserved_word_list.count)
Result.compare_objects
from Reserved_word_list.start until Reserved_word_list.after loop
Result.put (Reserved_word_list.item)
Reserved_word_list.forth
end
end
end