1% -*- SLang -*-         ruby.sl
2
3% Author:	MAEDA Shugo (shugo@po.aianet.ne.jp)
4% Version:	0.03
5
6% `Ruby mode for Jed' is FREESOFTWARE.
7% Please use AT YOUR OWN RISK.
8
9% [What's ruby?]
10%
11%  Ruby is the interpreted scripting language for quick and
12%  easy object-oriented programming.  It has many features to
13%  process text files and to do system management tasks (as in
14%  perl).  It is simple, straight-forward, and extensible.
15%
16%  The ruby distribution can be found on
17%
18%    ftp://ftp.netlab.co.jp/pub/lang/ruby/
19
20% [Install]
21%
22% Please add these lines to your `.jedrc' file.
23%
24%   ~/.jedrc
25%
26%     % amount of space to indent within block.
27%     variable ruby_indent_level = 2;
28%
29%     % Load ruby mode when openning `.rb' files.
30%     autoload("ruby_mode", "ruby");
31%     add_mode_for_extension ("ruby", "rb");
32
33variable ruby_mode_version = "0.0.3";
34
35!if (is_defined ("ruby_indent_level"))
36{
37    variable ruby_indent_level = 2;
38}
39
40define ruby_show_version()
41{
42    message(Sprintf("ruby mode for Jed version %s", ruby_mode_version, 1));
43}
44
45define ruby_indent_to(n)
46{
47    variable step;
48
49    step = what_column();
50    bol_skip_white();
51    step -= what_column();
52    if (what_column != n) {
53	bol_trim ();
54	n--;
55	whitespace (n);
56    }
57    if (step > 0) go_right(step);
58}
59
60define ruby_looking_keyword_at(keyword)
61{
62    push_spot;
63    EXIT_BLOCK {
64	pop_spot;
65    }
66
67    if (looking_at(keyword)) {
68	go_right(strlen(keyword));
69	return (orelse
70	       { looking_at(" ") }
71	       { looking_at("\t") }
72	       { looking_at(";") }
73	       { eolp() }
74		);
75    } else {
76	return 0;
77    }
78}
79
80define ruby_calculate_indent()
81{
82    variable indent = 0;
83    variable extra_indent = 0;
84    variable ch;
85    variable par_level;
86
87    CASE_SEARCH = 0;
88    push_spot();
89    EXIT_BLOCK {
90	pop_spot();
91    }
92
93    bol_skip_white();
94    indent = what_column();
95    if (orelse
96       { ruby_looking_keyword_at("end") }
97       { ruby_looking_keyword_at("else") }
98       { ruby_looking_keyword_at("elsif") }
99       { ruby_looking_keyword_at("rescue") }
100       { ruby_looking_keyword_at("ensure") }
101       { ruby_looking_keyword_at("when") }
102       { looking_at("}") }
103	) {
104	extra_indent -= ruby_indent_level;
105    }
106    !if (up_1()) return indent;
107
108    eol();
109    par_level = 0;
110    forever {
111	if (eolp()) {
112	    forever {
113		bol();
114		if (looking_at("#")) {
115		    !if (up_1()) return indent;
116		    eol();
117		} else {
118		    eol();
119		    break;
120		}
121	    }
122	}
123	go_left_1();
124	ch = what_char();
125	if (ch == ')') {
126	    par_level--;
127	} else if (ch == '(') {
128	    par_level++;
129	    if (par_level == 1) return what_column() + 1;
130	}
131
132	if (bolp() and (par_level == 0)) {
133	    skip_white();
134	    indent = what_column();
135	    break;
136	}
137    }
138
139    if (looking_at("#")) return what_column();
140
141    if (orelse
142       { ruby_looking_keyword_at("class") }
143       { ruby_looking_keyword_at("module") }
144       { ruby_looking_keyword_at("def") }
145       { ruby_looking_keyword_at("if") }
146       { ruby_looking_keyword_at("else") }
147       { ruby_looking_keyword_at("elsif") }
148       { ruby_looking_keyword_at("unless") }
149       { ruby_looking_keyword_at("case") }
150       { ruby_looking_keyword_at("when") }
151       { ruby_looking_keyword_at("while") }
152       { ruby_looking_keyword_at("until") }
153       { ruby_looking_keyword_at("for") }
154       { ruby_looking_keyword_at("begin") }
155       { ruby_looking_keyword_at("rescue") }
156       { ruby_looking_keyword_at("ensure") }
157	) {
158	eol();
159	bskip_white();
160	!if (orelse
161	    { blooking_at(" end") }
162	    { blooking_at("\tend") }
163	     ) {
164	    extra_indent += ruby_indent_level;
165	}
166    } else {
167	eol();
168	bskip_white();
169	if (blooking_at("{"))
170	    extra_indent += ruby_indent_level;
171	else if (blooking_at("|"))
172	    extra_indent += ruby_indent_level;
173	else if (blooking_at(" do"))
174	    extra_indent += ruby_indent_level;
175    }
176
177    return indent + extra_indent;
178}
179
180define ruby_indent_line()
181{
182    ruby_indent_to(ruby_calculate_indent());
183}
184
185define ruby_newline_and_indent()
186{
187    variable step;
188    step = what_column();
189    bol_skip_white();
190    step -= what_column();
191    if (orelse
192       { looking_at("end") }
193       { looking_at("else") }
194       { looking_at("elsif") }
195       { looking_at("rescue") }
196       { looking_at("ensure") }
197       { looking_at("when") }
198       { looking_at("}") }
199	) {
200	ruby_indent_line();
201    }
202    go_right(step);
203    newline();
204    ruby_indent_line();
205}
206
207define ruby_self_insert_cmd()
208{
209    variable step;
210
211%    insert(LAST_CHAR);
212    insert(char(LAST_CHAR));
213    step = what_column();
214    bol_skip_white();
215    step -= what_column();
216    if (orelse
217       { looking_at("end") }
218       { looking_at("else") }
219       { looking_at("elsif") }
220       { looking_at("rescue") }
221       { looking_at("ensure") }
222       { looking_at("when") }
223       { looking_at("}") }
224	) {
225	ruby_indent_line();
226    }
227    go_right(step);
228}
229
230% Define keymap.
231$1 = "ruby";
232!if (keymap_p($1)) make_keymap($1);
233definekey ("ruby_show_version", "^Cv", $1);
234definekey ("ruby_self_insert_cmd", "0", $1);
235definekey ("ruby_self_insert_cmd", "1", $1);
236definekey ("ruby_self_insert_cmd", "2", $1);
237definekey ("ruby_self_insert_cmd", "3", $1);
238definekey ("ruby_self_insert_cmd", "4", $1);
239definekey ("ruby_self_insert_cmd", "5", $1);
240definekey ("ruby_self_insert_cmd", "6", $1);
241definekey ("ruby_self_insert_cmd", "7", $1);
242definekey ("ruby_self_insert_cmd", "8", $1);
243definekey ("ruby_self_insert_cmd", "9", $1);
244definekey ("ruby_self_insert_cmd", "a", $1);
245definekey ("ruby_self_insert_cmd", "b", $1);
246definekey ("ruby_self_insert_cmd", "c", $1);
247definekey ("ruby_self_insert_cmd", "d", $1);
248definekey ("ruby_self_insert_cmd", "e", $1);
249definekey ("ruby_self_insert_cmd", "f", $1);
250definekey ("ruby_self_insert_cmd", "g", $1);
251definekey ("ruby_self_insert_cmd", "h", $1);
252definekey ("ruby_self_insert_cmd", "i", $1);
253definekey ("ruby_self_insert_cmd", "j", $1);
254definekey ("ruby_self_insert_cmd", "k", $1);
255definekey ("ruby_self_insert_cmd", "l", $1);
256definekey ("ruby_self_insert_cmd", "m", $1);
257definekey ("ruby_self_insert_cmd", "n", $1);
258definekey ("ruby_self_insert_cmd", "o", $1);
259definekey ("ruby_self_insert_cmd", "p", $1);
260definekey ("ruby_self_insert_cmd", "q", $1);
261definekey ("ruby_self_insert_cmd", "r", $1);
262definekey ("ruby_self_insert_cmd", "s", $1);
263definekey ("ruby_self_insert_cmd", "t", $1);
264definekey ("ruby_self_insert_cmd", "u", $1);
265definekey ("ruby_self_insert_cmd", "v", $1);
266definekey ("ruby_self_insert_cmd", "w", $1);
267definekey ("ruby_self_insert_cmd", "x", $1);
268definekey ("ruby_self_insert_cmd", "y", $1);
269definekey ("ruby_self_insert_cmd", "z", $1);
270definekey ("ruby_self_insert_cmd", "A", $1);
271definekey ("ruby_self_insert_cmd", "B", $1);
272definekey ("ruby_self_insert_cmd", "C", $1);
273definekey ("ruby_self_insert_cmd", "D", $1);
274definekey ("ruby_self_insert_cmd", "E", $1);
275definekey ("ruby_self_insert_cmd", "F", $1);
276definekey ("ruby_self_insert_cmd", "G", $1);
277definekey ("ruby_self_insert_cmd", "H", $1);
278definekey ("ruby_self_insert_cmd", "I", $1);
279definekey ("ruby_self_insert_cmd", "J", $1);
280definekey ("ruby_self_insert_cmd", "K", $1);
281definekey ("ruby_self_insert_cmd", "L", $1);
282definekey ("ruby_self_insert_cmd", "M", $1);
283definekey ("ruby_self_insert_cmd", "N", $1);
284definekey ("ruby_self_insert_cmd", "O", $1);
285definekey ("ruby_self_insert_cmd", "P", $1);
286definekey ("ruby_self_insert_cmd", "Q", $1);
287definekey ("ruby_self_insert_cmd", "R", $1);
288definekey ("ruby_self_insert_cmd", "S", $1);
289definekey ("ruby_self_insert_cmd", "T", $1);
290definekey ("ruby_self_insert_cmd", "U", $1);
291definekey ("ruby_self_insert_cmd", "V", $1);
292definekey ("ruby_self_insert_cmd", "W", $1);
293definekey ("ruby_self_insert_cmd", "X", $1);
294definekey ("ruby_self_insert_cmd", "Y", $1);
295definekey ("ruby_self_insert_cmd", "Z", $1);
296definekey ("ruby_self_insert_cmd", "_", $1);
297definekey ("ruby_self_insert_cmd", "{", $1);
298definekey ("ruby_self_insert_cmd", "}", $1);
299definekey ("ruby_self_insert_cmd", ";", $1);
300
301% Create syntax table.
302create_syntax_table ($1);
303define_syntax ("#", Null_String, '%', $1);
304define_syntax ("([{<", ")]}>", '(', $1);
305define_syntax ('"', '"', $1);
306define_syntax ('\'', '\'', $1);
307define_syntax ('\\', '\\', $1);
308define_syntax ("$0-9a-zA-Z_", 'w', $1);
309define_syntax ("-+0-9a-fA-F.xXL", '0', $1);
310define_syntax (",;.?:", ',', $1);
311define_syntax ("%-+/&*=<>|!~^", '+', $1);
312set_syntax_flags ($1, 4);
313
314#ifdef HAS_DFA_SYNTAX
315enable_highlight_cache("ruby.dfa", $1);
316define_highlight_rule("#.*$", "comment", $1);
317define_highlight_rule("([\\$%&@\\*]|\\$#)[A-Za-z_0-9]+", "normal", $1);
318define_highlight_rule(strcat("\\$([_\\./,\"\\\\#\\*\\?\\]\\[;!@:\\$<>\\(\\)",
319			     "%=\\-~\\^\\|&`'\\+]|\\^[A-Z])"), "normal", $1);
320define_highlight_rule("[A-Za-z_][A-Za-z_0-9]*", "Knormal", $1);
321define_highlight_rule("[0-9]+(\\.[0-9]+)?([Ee][\\+\\-]?[0-9]*)?", "number",
322		      $1);
323define_highlight_rule("0[xX][0-9A-Fa-f]*", "number", $1);
324define_highlight_rule("[\\(\\[\\{\\<\\>\\}\\]\\),;\\.\\?:]", "delimiter", $1);
325define_highlight_rule("[%\\-\\+/&\\*=<>\\|!~\\^]", "operator", $1);
326define_highlight_rule("-[A-Za-z]", "keyword0", $1);
327define_highlight_rule("'[^']*'", "string", $1);
328define_highlight_rule("'[^']*$", "string", $1);
329define_highlight_rule("\"([^\"\\\\]|\\\\.)*\"", "string", $1);
330define_highlight_rule("\"([^\"\\\\]|\\\\.)*\\\\?$", "string", $1);
331define_highlight_rule("m?/([^/\\\\]|\\\\.)*/[gio]*", "string", $1);
332define_highlight_rule("m/([^/\\\\]|\\\\.)*\\\\?$", "string", $1);
333define_highlight_rule("s/([^/\\\\]|\\\\.)*(/([^/\\\\]|\\\\.)*)?/[geio]*",
334		      "string", $1);
335define_highlight_rule("s/([^/\\\\]|\\\\.)*(/([^/\\\\]|\\\\.)*)?\\\\?$",
336		      "string", $1);
337define_highlight_rule("(tr|y)/([^/\\\\]|\\\\.)*(/([^/\\\\]|\\\\.)*)?/[cds]*",
338		      "string", $1);
339define_highlight_rule("(tr|y)/([^/\\\\]|\\\\.)*(/([^/\\\\]|\\\\.)*)?\\\\?$",
340		      "string", $1);
341define_highlight_rule(".", "normal", $1);
342build_highlight_table ($1);
343#endif
344
345% Type 0 keywords
346() = define_keywords_n ($1, "doifinor", 2, 0);
347() = define_keywords_n ($1, "anddefendfornilnot", 3, 0);
348() = define_keywords_n ($1, "caseelsefailloadloopnextredoselfthenwhen", 4, 0);
349() = define_keywords_n ($1, "aliasbeginbreakclasselsifraiseretrysuperundefuntilwhileyield", 5, 0);
350() = define_keywords_n ($1, "ensuremodulerescuereturnunless", 6, 0);
351() = define_keywords_n ($1, "includerequire", 7, 0);
352() = define_keywords_n ($1, "autoload", 8, 0);
353% Type 1 keywords (commonly used libc functions)
354() = define_keywords_n($1, "TRUEtrue", 4, 1);
355() = define_keywords_n($1, "FALSEfalse", 5, 1);
356
357define ruby_mode()
358{
359    variable kmap = "ruby";
360    set_mode(kmap, 2);
361   use_keymap(kmap);
362    use_syntax_table(kmap);
363    set_buffer_hook("indent_hook", "ruby_indent_line");
364    set_buffer_hook("newline_indent_hook", "ruby_newline_and_indent");
365    runhooks("ruby_mode_hook");
366}
367