# JOE syntax highlight file for Ruby

# Glitches:
# <<EOF1, <<EOF2 is not working.  Only EOF1 is seen.  It should wait for the
# EOF2.

=Idle
=Comment	green
=POD		green
=Constant	cyan
=Escape		bold cyan
=Type		bold
=Keyword	bold
=Bad		bold red
=Var		yellow
=Brace		magenta

=Symbol		red
=SymbolEscape	bold red
=ProcArg	#yellow
=ClassMember	yellow #fg_310 # brown
=GlobalVar	#yellow
=ClassDecl	bold blue

# Detect pod

:pre_idle Idle
	*		NULL		noeat call=.ruby()

.subr ruby

:idle Idle
	*		rest		noeat
	"="		pod_start

# Rest of line

:rest Idle
	*		rest
	"("		after_term	call=.ruby(paren)
	"["		after_term	call=.ruby(brack)
	"{"		do_brace	recolor=-1 noeat
.ifdef paren
	")"		rest		return
.else
	")"		stray		recolor=-1
.endif
.ifdef brack
	"]"		rest		return
.else
	"]"		stray		recolor=-1
.endif
.ifdef squiggly
	"}"		brace		recolor=-1 return
.else
	"}"		stray		recolor=-1
.endif
	"#"		line_comment	recolor=-1
.ifdef haml
	"\n"		NULL		return
.else
	"\n"		idle
.endif
	"0"		first_digit	recolor=-1
	"1-9"		decimal		recolor=-1
	"."		ident_no_kw
	"\""		string		recolor=-1
	"'"		char		recolor=-1
	"`"		backtick	recolor=-1
	"/"		regex		recolor=-1
	"<"		maybe_inc
	"$"		not_string	buffer
	"%"		pstring
	"\i"		ident		buffer
	"?"		opr

	# higher level, ruby specific
	":"		maybe_symbol
#	"|"		proc_arg
	"@"		class_member1

:opr Idle
	*		rest		noeat
	"/"		rest
	"%"		rest

:do_brace Brace
	*		rest		noeat
	"{"		brace		call=.ruby(squiggly)

:brace Brace
	*		after_term	noeat

:stray Bad
	*		rest


# / / regex not allowed after terms

:after_term Idle
	*		rest		noeat
	" \t"		after_term
.ifdef erb
	"/"		rest
	"%"		after_term_erb_end
.else
	"/%"		rest
.endif

:after_term_erb_end Idle
	*		rest		noeat
	">"		NULL		recolor=-2 return

:pod_start Idle
	*		pod_start
	"\n"		pod_block

:pod_block POD
	*		pod_block
	"="		pod_ident	buffer

:pod_ident POD
	*		pod_block	noeat strings
	"=end"		rest
done
	"\c"		pod_ident

:maybe_inc Idle
	*		after_term	noeat
	"<"		maybe_inc1

:maybe_inc1 Idle
	*		after_term	noeat
	"-"		allow_space
	"'\""		quoted_inc_start	save_c recolor=-1
	"\i"		inc		buffer noeat

:allow_space Idle
	*		after_term	noeat
	"'\""		quoted_inc_start_allow	save_c recolor=-1
	"\i"		inc_allow	buffer noeat

:quoted_inc_start Var
	*		quoted_inc	buffer

:quoted_inc_start_allow Var
	*		quoted_inc_allow	buffer

:quoted_inc Var
	*		quoted_inc
	&		skipline	save_s

:quoted_inc_allow Var
	*		quoted_inc_allow
	&		skipline_allow	save_s

:inc Var
	*		skipline	save_s noeat
	"\c"		inc

:inc_allow Var
	*		skipline_allow	save_s noeat
	"\c"		inc_allow

# Should be treated as a normal line here...

:skipline Idle
	*		skipline
	"\n"		next_line

:skipline_allow Idle
	*		skipline_allow
	"\n"		next_line_allow

:todelim Constant
	*		todelim
	"\n"		next_line	strings
	"&"		founddelim
done

:todelim_allow Constant
	*		todelim_allow
	"\n"		next_line_allow	strings
	"&"		founddelim
done

# eat \n so it's not in string.
:next_line Constant
	*		todelim		buffer
	"\n"		next_line

:next_line_allow Constant
	*		todelim_allow	buffer
	" \t\n"		next_line_allow

:founddelim Var
	*		idle		noeat

:regex Constant
	*		regex
	"\\"		regex_quote	recolor=-1
	"/"		after_term

:regex_quote Escape
	*		regex

:not_string Idle
	*		rest		noeat
	"\c"		global_var	recolor=-2
	"\"'`#/"	rest

:brace Brace
	*		rest		noeat

:line_comment Comment
	*		line_comment
.ifdef erb
	"%"		line_comment_maybe_erb_end
.endif
	# might be TODO label
	"BFHNTX"	line_comment	noeat call=comment_todo.comment_todo()
.ifdef haml
	"\n"		NULL		return
.else
	"\n"		idle
.endif

:line_comment_maybe_erb_end Comment
	">"		NULL		recolor=-2 return

:end_of_file_comment Comment
	*		end_of_file_comment

:first_digit Constant
	*		after_term	noeat
	"x"		hex
	"b"		binary
	"."		maybe_float
	"eE"		epart
	"0-7"		octal
	"89"		bad_number	recolor=-1

:bad_number Bad
	*		after_term	noeat
	"0-9"		bad_number

:octal Constant
	*		after_term	noeat
	"0-7_"		octal
	"89"		bad_number	recolor=-1

:binary Constant
	*		after_term	noeat
	"01_"		binary
	"2-9"		bad_number	recolor=-1

:hex Constant
	*		after_term	noeat
	"0-9A-Fa-f_"	hex

:decimal Constant
	*		after_term	noeat
	"0-9_"		decimal
	"eE"		epart
	"."		maybe_float

:maybe_float Idle
	*		after_term	noeat recolor=-2
	"0-9"		float		noeat

:float Constant
	*		after_term	noeat
	"eE"		epart
	"0-9_"		float

:epart Constant
	*		after_term	noeat
	"0-9+\-"	enum

:enum Constant
	*		after_term	noeat
	"0-9_"		enum

:string	Constant
	*		string
	"\""		after_term
	"\\"		string_escape	recolor=-1
	"#"		maybe_string_subst	recolor=-1

:maybe_string_subst Constant
	*		string		noeat
	"{"		string_subst	recolor=-2 call=.ruby(squiggly)

:string_subst Idle
	*		string		noeat
	
:string_escape Escape
	*		string
	"x"		string_hex1
	"c"		string_ctrl
	"N"		string_named
	"0-7"		string_octal2
	"\n"		string		recolor=-2

:string_named Escape
	*		string
	"{"		string_named_rest

:string_named_rest Escape
	*		string_named_rest
	"}"		string

:string_ctrl Escape
	*		string

:string_hex1 Escape
	*		string		noeat
	"{"		string_unicode
	"0-9a-fA-F"	string_hex2

:string_unicode Escape
	*		string_unicode
	"}"		string

:string_hex2 Escape
	*		string		noeat
	"0-9a-fA-F"	string

:string_octal2 Escape
	*		string		noeat
	"0-7"		string_octal3

:string_octal3 Escape
	*		string		noeat
	"0-7"		string

# Only \\ and \' allowed in single quoted strings

:char Constant
	*		char
	"\n"		reset
	"'"		after_term
	"\\"		char_escape	recolor=-1

:char_escape	Escape
	*		char		recolor=-2
	"\\'"	char

:backtick	Constant
	*		backtick
	"`"		after_term
	"\\"		backtick_escape	recolor=-1
	"$@"		backtick_subst	recolor=-1

:backtick_subst Escape
	*		backtick	noeat recolor=-1
	"\c"		backtick_subst

:backtick_escape Escape
	*		backtick
	"x"		backtick_hex1
	"c"		backtick_ctrl
	"N"		backtick_named
	"0-7"		backtick_octal2
	"\n"		backtick	recolor=-2

:backtick_named Escape
	*		backtick
	"{"		backtick_named_rest

:backtick_named_rest Escape
	*		backtick_named_rest
	"}"		backtick

:backtick_ctrl Escape
	*		backtick

:backtick_hex1 Escape
	*		backtick	noeat
	"{"		backtick_unicode
	"0-9a-fA-F"	backtick_hex2

:backtick_unicode Escape
	*		backtick_unicode
	"}"		backtick

:backtick_hex2 Escape
	*		backtick	noeat
	"0-9a-fA-F"	backtick

:backtick_octal2 Escape
	*		backtick	noeat
	"0-7"		backtick_octal3

:backtick_octal3 Escape
	*		backtick	noeat
	"0-7"		backtick

:ident_no_kw Idle
	*		after_term	noeat
	"0"		first_digit	recolor=-2
	"1-9"		decimal		recolor=-2
	"\i"		ident_no_kw1

:ident_no_kw1 Idle
	*		after_term	noeat
	"\c?!"		ident_no_kw1

:ident Idle
	*		after_term	noeat strings
	"BEGIN"		kw
	"END"		kw
	"alias"		kw_after
	"and"		kw
	"begin"		kw
	"break"		kw
	"case"		kw
	"catch"		kw
	"class"		kw_class
	"def"		kw_after
	"defined"	kw
	"do"		kw
	"else"		kw
	"elsif"		kw
	"end"		kw
	"ensure"	kw
	"fail"		kw
	"false"		kw
	"for"		kw
	"if"		kw
	"in"		kw
	"lambda"	kw
	"module"	kw
	"next"		kw
	"nil"		kw
	"not"		kw
	"or"		kw
	"private"	kw
	"proc"		kw
	"protected"	kw
	"public"	kw
	"raise"		kw
	"redo"		kw
	"rescue"	kw
	"retry"		kw
	"return"	kw
	"self"		kw_after
	"super"		kw
	"then"		kw
	"throw"		kw
	"true"		kw
	"undef"		kw
	"unless"	kw
	"until"		kw
	"when"		kw
	"while"		kw
	"yield"		kw
	# quasi-keywords (Module or Kernel methods)
	"require"	kw
	"autoload"	kw
	"extend"	kw
	"include"	kw
	"puts"		kw
	"exit"		kw
	"attr_accessor"	kw
	"attr_reader"	kw
	"attr_writer"	kw
	"module_function"	kw
done
	# allowing ?! is not nearly correct but fixes more than
	# it destructs
	"\c?!"	ident

:kw Keyword
	*		rest		noeat

# Handle case of def /
:kw_after Keyword
	*		after_term	noeat

:kw_class Keyword
	*		rest		noeat
	" \t\n"		kw_class_space

:kw_class_space Idle
	*		rest		noeat
	# first char should be uppercase letter
	"\i"		kw_class_decl	noeat
	" \t\n"		kw_class_space

:kw_class_decl ClassDecl
	*		rest		noeat
	"\c"		kw_class_decl

:pstring Idle
	*		match		noeat
	" \t"		after_term	noeat
	"xrsqQwW"	match
.ifdef erb
	">"		NULL		recolor=-2 return
.endif

:match Idle
	*		inmatch		save_c recolor=-1
	" \t"		match

:inmatch Constant
	*		inmatch
	&		after_term
	%		inmatch		call=.inmatch_recur()
	"#"		inmatch_maybe_subst
	"\\"		inmatch_quote	recolor=-1

:inmatch_maybe_subst Constant
	*		inmatch		noeat
	"{"		inmatch_subst	recolor=-2 call=.ruby(squiggly)

:inmatch_subst Idle
	*		inmatch		noeat

:inmatch_quote Escape
	*		inmatch

:subst Idle
	*		insubst		save_c recolor=-1
	"<([{`"		delim_insubst	save_c recolor=-1
	" \t"		subst

:insubst Constant
	*		insubst
	&		inrepl
	"\\"		insubst_quote	recolor=-1

:insubst_quote Escape
	*		insubst

:inrepl Constant
	*		inrepl
	&		after_term
	"\\"		inrepl_quote

:inrepl_quote Escape
	*		inrepl

:delim_insubst Constant
	*		delim_insubst
	&		delim_repl
	"\\"		delim_quote

:delim_quote Escape
	*		delim_insubst

:delim_repl Constant
	*		repl		save_c recolor=-1
	" \t"		delim_repl

:repl Constant
	*		repl
	&		after_term
	"\\"		repl_quote

:repl_quote Escape
	*		repl

:maybe_symbol Idle
	*		rest		noeat
	# prevent wrong Module::Member detection
	":"		rest
	# first char mustn't be 0-9
	"\i"		symbol		recolor=-2
	"\""		symbol_str	recolor=-2
	"'"		symbol_str_sq	recolor=-2
	"/"		rest

:symbol Symbol
	*		rest		noeat
	"\c?!"		symbol

:symbol_str Symbol
	*		symbol_str
	"\""		after_term
	"#"		symbol_maybe_str_subst	recolor=-1

:symbol_maybe_str_subst Symbol
	*		symbol_str
	"{"		symbol_str_subst	recolor=-2 call=.ruby(squiggly)

:symbol_str_subst Idle
	*		symbol_str		noeat

:symbol_str_sq Symbol
	*		symbol_str_sq
	"'"		after_term

:proc_arg ProcArg
	*		rest		noeat
	","		proc_arg_sep 	noeat
	"\i"		proc_arg
	
:proc_arg_sep Idle
	*		proc_arg
	
:class_member1 Idle
	*		rest		noeat
	"\i"		class_member	recolor=-2
	"@"		class_member2

:class_member2 ClassMember
	*		rest		noeat
	"\i"		class_member	recolor=-3

:class_member ClassMember
	*		after_term	noeat
	"\c"		class_member

:global_var GlobalVar
	*		after_term	noeat
	"\c"		global_var

.end

.subr inmatch_recur

:inmatch Constant
	*		inmatch
	&		after_term	return
	%		inmatch		call=.inmatch_recur()
	"#"		inmatch_maybe_subst
	"\\"		inmatch_quote	recolor=-1

:inmatch_maybe_subst Constant
	*		inmatch		noeat
	"{"		inmatch_subst	recolor=-2 call=.ruby(squiggly)

:inmatch_subst Idle
	*		inmatch		noeat

:inmatch_quote Escape
	*		inmatch

.end
