class MARKDOWN_TRANSLATER

(source code)

Description

Translates Eiffel-View publisher markdown to Github markdown

note
	description: "Translates Eiffel-View publisher markdown to Github markdown"

	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-08 18:01:15 GMT (Friday 8th January 2021)"
	revision: "6"

class
	MARKDOWN_TRANSLATER

inherit
	EL_PLAIN_TEXT_LINE_STATE_MACHINE
		rename
			make as make_machine
		end

	EL_ZSTRING_CONSTANTS

	MARKDOWN_ROUTINES

	SHARED_HTML_CLASS_SOURCE_TABLE

create
	make

feature {NONE} -- Initialization

	make (a_repository_web_address: like repository_web_address)
		do
			repository_web_address := a_repository_web_address
			create output.make_empty
			make_machine
		end

feature -- Basic operations

	to_github_markdown (markdown: EL_ZSTRING_LIST): ZSTRING
		-- return Eiffel-View publisher markdown lines as Github markdown
		local
			s: EL_ZSTRING_ROUTINES
		do
			output.wipe_out; output.extend (new_string)
			do_with_lines (agent add_normal_text, markdown)
			if not is_code_block then
				if last_is_line_item then
					output.last.append (s.character_string ('%N'))
				end
				translate (output.last)
			end
			Result := output.joined_lines
		end

feature {NONE} -- Line states

	add_normal_text (line: ZSTRING)
		local
			s: EL_ZSTRING_ROUTINES
		do
			if line.starts_with (s.character_string ('%T')) then
				translate (output.last)
				output.extend (Code_block_delimiter.twin)
				state := agent add_code_block
				is_code_block := True
				add_code_block (line)
			else
				if not output.last.is_empty then
					if line.is_empty then
						output.last.append (Double_new_line)
					elseif is_list_item (line) then
						output.last.append (s.character_string ('%N'))
					elseif not output.last.ends_with (Double_new_line) then
						output.last.append_character (' ')
					end
				end
				output.last.append (line)
				last_is_line_item := is_list_item (line)
			end
		end

	add_code_block (line: ZSTRING)
		local
			s: EL_ZSTRING_ROUTINES
		do
			output.last.append (s.character_string ('%N'))
			if line.starts_with (s.character_string ('%T')) then
				output.last.append (line.substring_end (2))
			else
				output.last.append (Code_block_delimiter)
				output.extend (new_string)
				state := agent add_normal_text
				is_code_block := False
				add_normal_text (line)
			end
		end

feature {NONE} -- Implementation

	translate (text: ZSTRING)
		do
			replace_links (text); replace_apostrophes (text)
			text.replace_substring_general_all ("''", "*")
		end

	new_string: ZSTRING
		do
			create Result.make_empty
		end

	replace_apostrophes (text: ZSTRING)
			-- change (`xx') to (`xx`) in order be compatible with Github markdown
		local
			pos_grave, pos_apostrophe: INTEGER; done: BOOLEAN
		do
			from done := False until done or pos_grave > text.count loop
				pos_grave := text.index_of ('`', pos_grave + 1)
				if pos_grave > 0 then
					pos_apostrophe := text.index_of ('%'', pos_grave + 1)
					if pos_apostrophe > 0 then
						text.put ('`', pos_apostrophe)
						pos_grave := pos_apostrophe
					end
				else
					done := True
				end
			end
		end

	replace_links (text: ZSTRING)
			-- change [http://address.com click here] to [click here](http://address.com)
			-- in order to be compatible with Github markdown
		do
			across Link_types as type loop
				text.edit (type.item, Right_bracket, agent to_github_link)
			end
		end

	to_github_link (start_index, end_index: INTEGER; substring: ZSTRING)
		local
			link_address, link_text: ZSTRING
			space_index: INTEGER
		do
			substring.to_canonically_spaced
			space_index := substring.index_of (' ', 1)
			if space_index > 0 then
				link_address := substring.substring (2, space_index - 1)
				link_text := substring.substring (space_index + 1, substring.count - 1)
				inspect link_address [1]
					when '.' then
						link_address.replace_substring (repository_web_address, 1, 1)
					when '$' then
						if Class_source_table.has_key (class_name (link_text)) then
							link_address := Join_path #$ [repository_web_address, Class_source_table.found_item]
						end
				else end
			else
				link_text := Empty_string
			end
			if link_text.is_empty then
				substring.share (substring.substring (2, substring.count - 1))
			else
				substring.share (Github_link #$ [link_text, link_address])
			end
		end

feature {NONE} -- Internal attributes

	output: EL_ZSTRING_LIST

	repository_web_address: ZSTRING

	is_code_block: BOOLEAN

	last_is_line_item: BOOLEAN

feature {NONE} -- Constants

	Code_block_delimiter: ZSTRING
		once
			create Result.make_filled ('`', 4)
		end

	Double_new_line: ZSTRING
		once
			Result := "%N%N"
		end

	Github_link: ZSTRING
		once
			Result := "[%S](%S)"
		end

	Join_path: ZSTRING
		once
			Result := "%S/%S"
		end

	Link_types: ARRAY [ZSTRING]
		once
			Result := << "[http://", "[https://", "[./", "[$source" >>
		end

	Right_bracket: ZSTRING
		once
			Result := "]"
		end
end