Mercurial > hg > xemacs-beta
comparison lisp/modes/ksh-mode.el @ 2:ac2d302a0011 r19-15b2
Import from CVS: tag r19-15b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:46:35 +0200 |
parents | 376386a54a3c |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
1:c0c6a60d29db | 2:ac2d302a0011 |
---|---|
1 ;; ksh-mode.el --- sh (ksh, bash) script editing mode for GNU Emacs. | 1 ;; ksh-mode.el --- sh (ksh, bash) script editing mode for GNU Emacs. |
2 | 2 |
3 ;; Copyright (C) 1992-95 Gary Ellison. | 3 ;; Copyright (C) 1992-96 Gary Ellison. |
4 | 4 |
5 ;; This file is part of XEmacs. | 5 ;; This file is part of XEmacs. |
6 | 6 |
7 ;; XEmacs is free software; you can redistribute it and/or modify it | 7 ;; XEmacs is free software; you can redistribute it and/or modify it |
8 ;; under the terms of the GNU General Public License as published by | 8 ;; under the terms of the GNU General Public License as published by |
16 | 16 |
17 ;; You should have received a copy of the GNU General Public License | 17 ;; You should have received a copy of the GNU General Public License |
18 ;; along with XEmacs; see the file COPYING. If not, write to the Free | 18 ;; along with XEmacs; see the file COPYING. If not, write to the Free |
19 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 19 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
20 | 20 |
21 ;; $Source: /afs/informatik.uni-tuebingen.de/local/web/xemacs/xemacs-cvs/XEmacs/xemacs-19/lisp/modes/ksh-mode.el,v $ -- | |
22 ;; | |
21 ;; LCD Archive Entry: | 23 ;; LCD Archive Entry: |
22 ;; ksh-mode|Gary F. Ellison|Gary_F_Ellison@ATT.COM | 24 ;; ksh-mode|Gary F. Ellison|Gary.F.Ellison@ATT.COM |
23 ;; Mode for editing sh/ksh/bash scripts | 25 ;; |Mode for editing sh/ksh/bash scripts |
24 ;; 23-Feb-95|2.6|~/modes/ksh-mode.el.Z| | 26 ;; |$Date: 1996/12/18 03:44:42 $|$Revision: 1.1.1.2 $|~/modes/ksh-mode.el.Z| |
25 | 27 |
26 ;; Author: Gary F. Ellison <Gary.F.Ellison@ATT.COM> | 28 ;; Author: Gary F. Ellison <Gary.F.Ellison@ATT.COM> |
27 ;; AT&T Bell Laboratories | 29 ;; AT&T Laboratories |
28 ;; 6200 East Broad Street | 30 ;; 6200 East Broad Street |
29 ;; Columbus, Ohio 43213 USA | 31 ;; Columbus, Ohio 43213 USA |
30 ;; | 32 ;; |
31 ;; Maintainer: Gary F. Ellison <Gary.F.Ellison@ATT.COM> | 33 ;; Maintainer: Gary F. Ellison <Gary.F.Ellison@ATT.COM> |
32 ;; Created: Fri Jun 19 | 34 ;; Created: Fri Jun 19 |
33 ;; Version: 2.6 | 35 ;; $Revision: 1.1.1.2 $ |
34 ;; Keywords: languages, shell, korn, bourne, sh, ksh, bash, unix | 36 ;; Keywords: shell, korn, bourne, sh, ksh, bash |
35 ;; | 37 ;; |
36 ;; Delta On : 2/23/95 | 38 ;; Delta On $Date: 1996/12/18 03:44:42 $ |
37 ;; Last Modified By: Gary Ellison | 39 ;; Last Modified By: Gary Ellison |
38 ;; Last Modified On: Thu Feb 23 11:32:03 1995 | 40 ;; Last Modified On: Mon Sep 11 12:26:47 1995 |
39 ;; Update Count : 33 | 41 ;; Update Count : 35 |
40 ;; Status : Highly Functional | 42 ;; Status : Highly Functional |
41 ;; | 43 ;; |
42 | 44 |
43 ;;; Commentary: | 45 ;;; Commentary: |
44 | 46 |
76 ;;; Code: | 78 ;;; Code: |
77 | 79 |
78 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 80 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
79 ;; | 81 ;; |
80 ;; HISTORY | 82 ;; HISTORY |
83 ;; 6-Apr-96 Gary Ellison <gary.f.ellison@att.com> | |
84 ;; Depreciated font-lock-doc-string-face. | |
85 ;; Narly keywords inside strings bug fixed. | |
86 ;; | |
81 ;; 8-Aug-95 Jack Repenning <jackr@sgi.com> | 87 ;; 8-Aug-95 Jack Repenning <jackr@sgi.com> |
82 ;; Fix documentation of `ksh-align-to-keyword' to conform to the 23 | 88 ;; Fix documentation of `ksh-align-to-keyword' to conform to the 23 |
83 ;; Feb default change. Search for keywords obeying case, since the | 89 ;; Feb default change. Search for keywords obeying case, since the |
84 ;; shell does. | 90 ;; shell does. |
85 ;; | 91 ;; |
222 ;; 19-Jun-1992 Gary Ellison | 228 ;; 19-Jun-1992 Gary Ellison |
223 ;; Last Modified: Fri Jun 19 10:03:07 1992 #1 (Gary Ellison) | 229 ;; Last Modified: Fri Jun 19 10:03:07 1992 #1 (Gary Ellison) |
224 ;; Conception of this mode. | 230 ;; Conception of this mode. |
225 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 231 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
226 | 232 |
227 (defconst ksh-mode-version "2.6" | 233 (defconst ksh-mode-version "$Revision: 1.1.1.2 $" |
228 "*Version numbers of this version of ksh-mode") | 234 "*Version numbers of this version of ksh-mode") |
229 | 235 |
230 ;; | 236 ;; |
231 ;; Variables controlling indentation style | 237 ;; Variables controlling indentation style |
232 ;; | 238 ;; |
260 ;; #### - this is broken, so it should be disabled by default --Stig | 266 ;; #### - this is broken, so it should be disabled by default --Stig |
261 "*Controls whether nested constructs align from the keyword or | 267 "*Controls whether nested constructs align from the keyword or |
262 the current indentation. If non-nil, indentation will be relative to | 268 the current indentation. If non-nil, indentation will be relative to |
263 the column the keyword starts. If nil, indentation will be relative to | 269 the column the keyword starts. If nil, indentation will be relative to |
264 the current indentation of the line the keyword is on. | 270 the current indentation of the line the keyword is on. |
265 The default value is nil. | 271 The default value is non-nil. The non-nil case doesn't work very well.") |
266 The non-nil case doesn't work very well.") | |
267 | 272 |
268 (defvar ksh-comment-regexp "^\\s *#" | 273 (defvar ksh-comment-regexp "^\\s *#" |
269 "*Regular expression used to recognize comments. Customize to support | 274 "*Regular expression used to recognize comments. Customize to support |
270 ksh-like languages.") | 275 ksh-like languages.") |
271 | 276 |
299 ;; | 304 ;; |
300 ;; Variable controlling fontification | 305 ;; Variable controlling fontification |
301 ;; | 306 ;; |
302 (defvar ksh-keywords '("for" "in" "do" "done" "select" "case" "esac" "if" | 307 (defvar ksh-keywords '("for" "in" "do" "done" "select" "case" "esac" "if" |
303 "then" "elif" "else" "fi" "while" "until" "function" "time" | 308 "then" "elif" "else" "fi" "while" "until" "function" "time" |
304 "alias" "bg" "break" "continue" "cd" "echo" "fc" "fg" "getopts" "jobs" "kill" | 309 "alias" "bg" "break" "continue" "cd" "exit" "echo" "fc" "fg" "getopts" "jobs" |
305 "let" "newgrp" "print" "pwd" "read" "readonly" "return" "set" "shift" "test" | 310 "kill" "let" "newgrp" "print" "pwd" "read" "readonly" "return" "set" "shift" |
306 "times" "trap" "typeset" "ulimit" "umask" "unalias" "unset" "wait" "whence")) | 311 "test" "times" "trap" "typeset" "ulimit" "umask" "unalias" "unset" "wait" "whence")) |
307 | 312 |
308 ;; '("\\<function[ \t]+\\([^(; \t]+\\)" 1 font-lock-function-name-face) | 313 ;; '("\\<function[ \t]+\\([^(; \t]+\\)" 1 font-lock-function-name-face) |
309 (defconst ksh-font-lock-keywords | 314 (defconst ksh-font-lock-keywords |
310 (list | 315 (list |
311 ;; Fontify [[ ]] expressions | 316 ;; Fontify [[ ]] expressions |
312 '("\\(\\[.*\\]\\)" 1 font-lock-doc-string-face t) | 317 '("\\(\\[.*\\]\\)" 1 font-lock-string-face t) |
313 ;; Fontify keywords | 318 ;; Fontify keywords |
314 (cons (concat | 319 (cons (concat |
315 "\\(\\<" | 320 "\\(\\<" |
316 (mapconcat 'identity ksh-keywords "\\>\\|\\<") | 321 (mapconcat 'identity ksh-keywords "\\>\\|\\<") |
317 "\\>\\)") | 322 "\\>\\)") |
319 ;; Fontify function names | 324 ;; Fontify function names |
320 '("\\<function[ \t]+\\([^(; \t]+\\)" 1 font-lock-function-name-face) | 325 '("\\<function[ \t]+\\([^(; \t]+\\)" 1 font-lock-function-name-face) |
321 '("\\(^[ \t]*[A-Za-z_][A-Za-z_0-9]*[ \t]*()\\)" 1 font-lock-function-name-face) | 326 '("\\(^[ \t]*[A-Za-z_][A-Za-z_0-9]*[ \t]*()\\)" 1 font-lock-function-name-face) |
322 )) | 327 )) |
323 | 328 |
329 ;; XEmacs addition | |
324 (put 'ksh-mode 'font-lock-keywords 'ksh-font-lock-keywords) | 330 (put 'ksh-mode 'font-lock-keywords 'ksh-font-lock-keywords) |
325 | |
326 ;; XEmacs change -- This can incorrectly set some Perl scripts to | |
327 ;; ksh-mode. It also won't work for some other shells which ksh-mode | |
328 ;; nominally works with. | |
329 ;(defun ksh-check-hook () | |
330 ; (save-excursion | |
331 ; (save-restriction | |
332 ; (widen) | |
333 ; (goto-char (point-min)) | |
334 ; (cond ((looking-at "#![ \t]*/.*/k?sh[ \t]*") | |
335 ; (ksh-mode)))))) | |
336 ; | |
337 ;(add-hook 'find-file-hooks 'ksh-check-hook) | |
338 | 331 |
339 ;; | 332 ;; |
340 ;; Context/indentation regular expressions | 333 ;; Context/indentation regular expressions |
341 ;; | 334 ;; |
342 ;; indenting expressions | 335 ;; indenting expressions |
343 ;; | 336 ;; |
344 (defconst ksh-then-do-re "^[^#\n]*\\s\"*\\b\\(then\\|do\\)\\b" | 337 ;(defconst ksh-then-do-re "^[^#\n]*\\s\"*\\b\\(then\\|do\\)\\b" |
338 (defconst ksh-then-do-re "\\s *\\b\\(then\\|do\\)\\b" | |
345 "*Regexp used to locate grouping keywords: \"then\" and \"do\"" ) | 339 "*Regexp used to locate grouping keywords: \"then\" and \"do\"" ) |
346 | 340 |
347 ;;(defconst ksh-do-re "^[ \t]*\\bdo\\(\\b\\|$\\)" | 341 (defconst ksh-do-re "\\s *\\bdo\\(\\b\\|$\\)" |
348 (defconst ksh-do-re "^\\s *\\bdo\\(\\b\\|$\\)" | |
349 "*Regexp used to match keyword: do") | 342 "*Regexp used to match keyword: do") |
350 | 343 |
351 (defconst ksh-then-re "^\\s *\\bthen\\(\\b\\|$\\)" | 344 (defconst ksh-then-re "\\s *\\bthen\\(\\b\\|$\\)" |
352 "*Regexp used to match keyword: then") | 345 "*Regexp used to match keyword: then") |
353 | 346 |
354 ;; | 347 ;; |
355 ;; Structure starting/indenting keywords | 348 ;; Structure starting/indenting keywords |
356 ;; | 349 ;; |
357 (defconst ksh-else-re "^\\s *\\belse\\(\\b\\|$\\)" | 350 (defconst ksh-else-re "\\s *\\belse\\(\\b\\|$\\)" |
358 "*Regexp used to match keyword: else") | 351 "*Regexp used to match keyword: else") |
359 | 352 |
360 (defconst ksh-elif-re "^\\s *\\belif\\(\\b\\|$\\)" | 353 (defconst ksh-elif-re "\\s *\\belif\\(\\b\\|$\\)" |
361 "*Regexp used to match keyword: elif") | 354 "*Regexp used to match keyword: elif") |
362 | 355 |
363 (defconst ksh-brace-re "^\\S>*{[ \t\n]" | 356 (defconst ksh-brace-re "\\S>*{[ \t\n]" |
364 "*Regexp used to match syntactic entity: { ") | 357 "*Regexp used to match syntactic entity: { ") |
365 | 358 |
366 (defconst ksh-case-item-end-re "^\\S>*;;[ \t\n]" | 359 (defconst ksh-case-item-end-re "\\S>*;;[ \t\n]" |
367 "*Regexp used to match case item end syntactic entity: ;;") | 360 "*Regexp used to match case item end syntactic entity: ;;") |
368 | 361 |
369 (defconst ksh-keywords-re | 362 (defconst ksh-keywords-re |
370 "^[^#\n]*\\s\"*\\b\\(else\\|if\\|elif\\|case\\|while\\|for\\|until\\|select\\)\\b" | 363 "\\s *\\b\\(else\\|if\\|elif\\|case\\|while\\|for\\|until\\|select\\)\\b" |
371 "*Regexp used to detect compound command keywords: if, else, elif case, | 364 "*Regexp used to detect compound command keywords: if, else, elif case, |
372 while, for, until, and select") | 365 while, for, until, and select") |
373 | 366 |
374 | 367 |
375 (defconst ksh-if-re "^[^#\n]*\\s\"*\\b\\(if\\)\\b" | 368 (defconst ksh-if-re "\\s *\\b\\(if\\)\\b" |
376 "*Regexp used to match keyword: if") | 369 "*Regexp used to match keyword: if") |
377 | 370 |
378 (defconst ksh-iteration-keywords-re | 371 (defconst ksh-iteration-keywords-re |
379 "^[^#\n]*\\s\"*\\b\\(while\\|for\\|until\\|select\\)\\b" | 372 "\\s *\\b\\(while\\|for\\|until\\|select\\)\\b" |
380 "*Match one of the keywords: while, until, for, select") | 373 "*Match one of the keywords: while, until, for, select") |
381 | 374 |
382 (defconst ksh-case-re "^[^#\n]*\\s\"*\\b\\(case\\)\\b" | 375 (defconst ksh-case-re "\\s *\\bcase\\b" |
383 "*Regexp used to match keyword: case") | 376 "*Regexp used to match keyword: case") |
384 | 377 |
385 (defconst ksh-explicit-func-re | 378 (defconst ksh-explicit-func-re |
386 "^\\s *\\(function\\s [a-zA-z_][a-zA-Z0-1_]*\\)\\b" | 379 "^\\s *\\(function\\s [a-zA-z_][a-zA-Z0-1_]*\\)\\b" |
387 "*Match an explicit function definition: function name") | 380 "*Match an explicit function definition: function name") |
401 (defconst ksh-paren-re "^[^#\n]*\\s\"*)[ \t\n]+" | 394 (defconst ksh-paren-re "^[^#\n]*\\s\"*)[ \t\n]+" |
402 "*Regexp used to match compound list & case items") | 395 "*Regexp used to match compound list & case items") |
403 | 396 |
404 ;; | 397 ;; |
405 ;; structure ending keyword regular expressions | 398 ;; structure ending keyword regular expressions |
406 (defconst ksh-fi-re "^\\s *fi\\b" | 399 (defconst ksh-fi-re "\\s *\\bfi\\b" |
407 "*Regexp used to match keyword: fi") | 400 "*Regexp used to match keyword: fi") |
408 | 401 |
409 (defconst ksh-esac-re "^\\s *esac\\b" | 402 (defconst ksh-esac-re "\\s *\\besac\\b" |
410 "*Regexp used to match keyword: esac") | 403 "*Regexp used to match keyword: esac") |
411 | 404 |
412 (defconst ksh-done-re "^\\s *done\\b" | 405 (defconst ksh-done-re "\\s *\\bdone\\b" |
413 "*Regexp used to match keyword: done") | 406 "*Regexp used to match keyword: done") |
414 | 407 |
415 (defconst ksh-brace-end-re "^\\s *}\\s *" | 408 (defconst ksh-brace-end-re "\\s *}\\s *" |
416 "*Regexp used to match function brace-groups") | 409 "*Regexp used to match function brace-groups") |
417 | 410 |
418 (defconst ksh-multiline-re "^.*\\\\$" | 411 (defconst ksh-multiline-re "^.*\\\\$" |
419 "*Regexp used to match a line with a statement using more lines.") | 412 "*Regexp used to match a line with a statement using more lines.") |
420 | 413 |
423 ;; Create mode specific tables | 416 ;; Create mode specific tables |
424 (defvar ksh-mode-syntax-table nil | 417 (defvar ksh-mode-syntax-table nil |
425 "Syntax table used while in ksh mode.") | 418 "Syntax table used while in ksh mode.") |
426 (if ksh-mode-syntax-table | 419 (if ksh-mode-syntax-table |
427 () | 420 () |
428 (setq ksh-mode-syntax-table (make-syntax-table)) | 421 (setq ksh-mode-syntax-table (make-syntax-table (standard-syntax-table))) |
422 (modify-syntax-entry ?\( "." ksh-mode-syntax-table) | |
423 (modify-syntax-entry ?\) "." ksh-mode-syntax-table) | |
424 (modify-syntax-entry ?{ "." ksh-mode-syntax-table) | |
425 (modify-syntax-entry ?} "." ksh-mode-syntax-table) | |
426 (modify-syntax-entry ?\[ "(]" ksh-mode-syntax-table) | |
427 (modify-syntax-entry ?\] ")[" ksh-mode-syntax-table) | |
429 (modify-syntax-entry ?\' "\"" ksh-mode-syntax-table) | 428 (modify-syntax-entry ?\' "\"" ksh-mode-syntax-table) |
430 (modify-syntax-entry ?` "\"" ksh-mode-syntax-table) | 429 (modify-syntax-entry ?` "\"" ksh-mode-syntax-table) |
431 (modify-syntax-entry ?\n ">" ksh-mode-syntax-table) | 430 (modify-syntax-entry ?\n ">" ksh-mode-syntax-table) |
432 (modify-syntax-entry ?\f ">" ksh-mode-syntax-table) | 431 (modify-syntax-entry ?\f ">" ksh-mode-syntax-table) |
433 (modify-syntax-entry ?# "<" ksh-mode-syntax-table) | 432 (modify-syntax-entry ?# "<" ksh-mode-syntax-table) |
434 (modify-syntax-entry ?_ "w" ksh-mode-syntax-table) | 433 (modify-syntax-entry ?_ "w" ksh-mode-syntax-table) |
435 (modify-syntax-entry ?< "." ksh-mode-syntax-table) | 434 (modify-syntax-entry ?< "." ksh-mode-syntax-table) |
436 (modify-syntax-entry ?> "." ksh-mode-syntax-table) | 435 (modify-syntax-entry ?> "." ksh-mode-syntax-table) |
437 (modify-syntax-entry ?& "." ksh-mode-syntax-table) | 436 (modify-syntax-entry ?& "." ksh-mode-syntax-table) |
438 (modify-syntax-entry ?| "." ksh-mode-syntax-table) | 437 (modify-syntax-entry ?| "." ksh-mode-syntax-table) |
439 (modify-syntax-entry ?$ "." ksh-mode-syntax-table) | 438 (modify-syntax-entry ?$ "\\" ksh-mode-syntax-table) |
440 (modify-syntax-entry ?% "." ksh-mode-syntax-table) | 439 (modify-syntax-entry ?% "." ksh-mode-syntax-table) |
441 (modify-syntax-entry ?= "." ksh-mode-syntax-table) | 440 (modify-syntax-entry ?= "." ksh-mode-syntax-table) |
442 (modify-syntax-entry ?/ "." ksh-mode-syntax-table) | 441 (modify-syntax-entry ?/ "." ksh-mode-syntax-table) |
443 (modify-syntax-entry ?+ "." ksh-mode-syntax-table) | 442 (modify-syntax-entry ?+ "." ksh-mode-syntax-table) |
444 (modify-syntax-entry ?* "." ksh-mode-syntax-table) | 443 (modify-syntax-entry ?* "." ksh-mode-syntax-table) |
445 (modify-syntax-entry ?- "." ksh-mode-syntax-table) | 444 (modify-syntax-entry ?- "." ksh-mode-syntax-table) |
446 (modify-syntax-entry ?\; "." ksh-mode-syntax-table) | 445 (modify-syntax-entry ?\; "." ksh-mode-syntax-table) |
446 (modify-syntax-entry ?: "." ksh-mode-syntax-table) | |
447 ) | 447 ) |
448 | 448 |
449 (defvar ksh-mode-abbrev-table nil | 449 (defvar ksh-mode-abbrev-table nil |
450 "Abbrev table used while in ksh mode.") | 450 "Abbrev table used while in ksh mode.") |
451 (define-abbrev-table 'ksh-mode-abbrev-table ()) | 451 (define-abbrev-table 'ksh-mode-abbrev-table ()) |
455 | 455 |
456 (if ksh-mode-map | 456 (if ksh-mode-map |
457 () | 457 () |
458 (setq ksh-mode-map (make-sparse-keymap)) | 458 (setq ksh-mode-map (make-sparse-keymap)) |
459 (define-key ksh-mode-map "\t" 'ksh-indent-command) | 459 (define-key ksh-mode-map "\t" 'ksh-indent-command) |
460 ;; (define-key ksh-mode-map "\n" 'reindent-then-newline-and-indent) | |
461 ;; (define-key ksh-mode-map '[return] 'reindent-then-newline-and-indent) | |
462 ;; (define-key ksh-mode-map "\t" 'ksh-indent-line) | 460 ;; (define-key ksh-mode-map "\t" 'ksh-indent-line) |
463 ;; (define-key ksh-mode-map "\177" 'backward-delete-char-untabify) | 461 ;; (define-key ksh-mode-map "\177" 'backward-delete-char-untabify) |
464 (define-key ksh-mode-map "\C-j" 'reindent-then-newline-and-indent) | 462 (define-key ksh-mode-map "\C-j" 'reindent-then-newline-and-indent) |
465 (define-key ksh-mode-map "\e\t" 'ksh-complete-symbol) | 463 (define-key ksh-mode-map "\e\t" 'ksh-complete-symbol) |
466 (define-key ksh-mode-map "\C-c\t" 'ksh-completion-init-and-pickup) | 464 (define-key ksh-mode-map "\C-c\t" 'ksh-completion-init-and-pickup) |
467 ) | 465 ) |
468 | 466 |
469 | 467 |
470 ;;;###autoload | 468 ;;;###autoload |
471 (defun ksh-mode () | 469 (defun ksh-mode () |
472 "ksh-mode 2.6 - Major mode for editing (Bourne, Korn or Bourne again) | 470 "ksh-mode $Revision: 1.1.1.2 $ - Major mode for editing (Bourne, Korn or Bourne again) |
473 shell scripts. | 471 shell scripts. |
474 Special key bindings and commands: | 472 Special key bindings and commands: |
475 \\{ksh-mode-map} | 473 \\{ksh-mode-map} |
476 Variables controlling indentation style: | 474 Variables controlling indentation style: |
477 ksh-indent | 475 ksh-indent |
564 bar;; | 562 bar;; |
565 esac | 563 esac |
566 | 564 |
567 | 565 |
568 Installation: | 566 Installation: |
569 Put ksh-mode.el in some directory in your load-path. | |
570 Put the following forms in your .emacs file. | |
571 | |
572 (setq auto-mode-alist | |
573 (append auto-mode-alist | |
574 (list | |
575 '(\"\\\\.sh$\" . ksh-mode) | |
576 '(\"\\\\.ksh$\" . ksh-mode) | |
577 '(\"\\\\.bashrc\" . ksh-mode) | |
578 '(\"\\\\..*profile\" . ksh-mode)))) | |
579 | 567 |
580 (setq ksh-mode-hook | 568 (setq ksh-mode-hook |
581 (function (lambda () | 569 (function (lambda () |
582 (font-lock-mode 1) ;; font-lock the buffer | 570 (font-lock-mode 1) ;; font-lock the buffer |
583 (setq ksh-indent 8) | 571 (setq ksh-indent 8) |
584 (setq ksh-group-offset -8)) | 572 (setq ksh-group-offset -8) |
585 (setq ksh-brace-offset -8) | 573 (setq ksh-brace-offset -8) |
586 (setq ksh-tab-always-indent t) | 574 (setq ksh-tab-always-indent t) |
587 (setq ksh-match-and-tell t) | 575 (setq ksh-match-and-tell t) |
588 (setq ksh-align-to-keyword t) ;; Turn on keyword alignment | 576 (setq ksh-align-to-keyword t) ;; Turn on keyword alignment |
589 )))" | 577 )))" |
578 ;; | |
579 ;; and away we go | |
590 (interactive) | 580 (interactive) |
591 (kill-all-local-variables) | 581 (kill-all-local-variables) |
592 (use-local-map ksh-mode-map) | 582 (use-local-map ksh-mode-map) |
593 (setq major-mode 'ksh-mode) | 583 (setq major-mode 'ksh-mode) |
594 (setq mode-name "Ksh") | 584 (setq mode-name "Ksh") |
661 | 651 |
662 (defun ksh-get-nest-level () | 652 (defun ksh-get-nest-level () |
663 "Return a 2 element list (nest-level nest-line) describing where the | 653 "Return a 2 element list (nest-level nest-line) describing where the |
664 current line should nest." | 654 current line should nest." |
665 (let ((case-fold-search) | 655 (let ((case-fold-search) |
666 (level)) | 656 (level)) |
667 (save-excursion | 657 (save-excursion |
668 (forward-line -1) | 658 (forward-line -1) |
669 (while (and (not (bobp)) | 659 (while (and (not (bobp)) |
670 (null level)) | 660 (null level)) |
671 (if (and (not (looking-at "^\\s *$")) | 661 (if (and (not (looking-at "^\\s *$")) |
713 ) | 703 ) |
714 )) | 704 )) |
715 ) | 705 ) |
716 ) ;; defun | 706 ) ;; defun |
717 | 707 |
708 | |
718 (defun ksh-get-case-indent () | 709 (defun ksh-get-case-indent () |
719 "Return the column of the closest open case statement" | 710 "Return the column of the closest open case statement" |
720 (save-excursion | 711 (save-excursion |
721 (let ( | 712 (let ( |
722 (nest-list (ksh-get-compound-level ksh-case-re ksh-esac-re (point))) | 713 (nest-list (ksh-get-compound-level ksh-case-re ksh-esac-re (point))) |
728 0) | 719 0) |
729 (car nest-list))) | 720 (car nest-list))) |
730 ) | 721 ) |
731 ) | 722 ) |
732 | 723 |
724 | |
733 ;; | 725 ;; |
734 ;; Functions which make this mode what it is | 726 ;; Functions which make this mode what it is |
735 ;; | 727 ;; |
736 | 728 |
737 (defun ksh-get-nester-column (nest-line) | 729 (defun ksh-get-nester-column (nest-line) |
738 "Return the column to indent to with respect to nest-line taking | 730 "Return the column to indent to with respect to nest-line taking |
739 into consideration keywords and other nesting constructs." | 731 into consideration keywords and other nesting constructs." |
740 (save-excursion | 732 (save-excursion |
741 (let ((fence-post) | 733 (let ((fence-post) |
734 ; (start-post) | |
742 (nester-column) | 735 (nester-column) |
743 (case-fold-search) | 736 (case-fold-search) |
744 (start-line (ksh-current-line))) | 737 (start-line (ksh-current-line))) |
745 ;; | 738 (cond |
746 ;; Handle case item indentation constructs for this line | 739 ;; |
747 (cond ((ksh-looking-at-case-item) | 740 ;; Handle case item indentation constructs for this line |
748 (save-excursion | 741 ((ksh-looking-at-case-item) |
749 (goto-line nest-line) | 742 (save-excursion |
750 (let ((fence-post (save-excursion (end-of-line) (point)))) | 743 (goto-line nest-line) |
751 ;; | 744 (back-to-indentation) |
752 ;; Now know there is a case-item so detect whether | 745 (let ((fence-post (ksh-eol-point))) |
753 ;; it is first under case, just another case-item, or | 746 ;; |
754 ;; a case-item and case-item-end all rolled together. | 747 ;; Now know there is a case-item so detect whether |
755 ;; | 748 ;; it is first under case, just another case-item, or |
756 (cond ((re-search-forward ksh-case-re fence-post t) | 749 ;; a case-item and case-item-end all rolled together. |
757 (goto-char (match-beginning 1)) | 750 ;; |
758 (+ (ksh-current-indentation) ksh-case-item-offset)) | 751 (cond ((ksh-search-forward-sexp ksh-case-re fence-post) |
759 | 752 (+ (ksh-current-indentation) ksh-case-item-offset)) |
760 ((ksh-looking-at-case-item) | 753 |
761 (current-indentation)) | 754 ((ksh-looking-at-case-item) |
762 | 755 (current-indentation)) |
763 ((looking-at ksh-case-item-end-re) | 756 |
764 (end-of-line) | 757 ((looking-at ksh-case-item-end-re) |
765 (+ (ksh-get-case-indent) ksh-case-item-offset)) | 758 (end-of-line) |
766 ) | 759 (+ (ksh-get-case-indent) ksh-case-item-offset)) |
767 ))) | 760 ) |
768 (t;; Not a case-item. What to do relative to the nest-line? | 761 ))) |
769 (save-excursion | 762 (t;; Not a case-item. What to do relative to the nest-line? |
770 (goto-line nest-line) | 763 (save-excursion |
771 (setq fence-post (save-excursion (end-of-line) (point))) | 764 (goto-line nest-line) |
772 (setq nester-column | 765 ; (setq start-post (point)) |
773 (save-excursion | 766 (setq fence-post (ksh-eol-point)) |
774 (cond | 767 (setq nester-column |
775 ;; | 768 (save-excursion |
776 ;; Check if we are in a continued statement | 769 (cond |
777 ((and (looking-at ksh-multiline-re) | 770 ;; |
778 (save-excursion | 771 ;; Check if we are in a continued statement |
779 (goto-line (1- start-line)) | 772 ((and (looking-at ksh-multiline-re) |
780 (looking-at ksh-multiline-re))) | 773 (save-excursion |
781 (+ (current-indentation) ksh-multiline-offset)) | 774 (goto-line (1- start-line)) |
782 | 775 (looking-at ksh-multiline-re))) |
783 ;; In order to locate the column of the keyword, | 776 (+ (current-indentation) ksh-multiline-offset)) |
784 ;; which might be embedded within a case-item, | 777 ;; In order to locate the column of the keyword, |
785 ;; it is necessary to use re-search-forward. | 778 ;; which might be embedded within a case-item, |
786 ;; Search by literal case, since shell is | 779 ;; it is necessary to iterate over sexp. |
787 ;; case-sensitive. | 780 ((progn |
788 ((re-search-forward ksh-keywords-re fence-post t) | 781 (save-excursion |
789 (goto-char (match-beginning 1)) | 782 (back-to-indentation) |
790 (if (looking-at ksh-case-re) | 783 (if (ksh-search-forward-sexp ksh-keywords-re fence-post) |
791 (+ (ksh-current-indentation) ksh-case-item-offset) | 784 (progn |
792 (+ (ksh-current-indentation) | 785 ;; |
786 ;; special pun intended 'case' | |
787 (if (looking-at ksh-case-re) | |
788 (+ (ksh-current-indentation) | |
789 ksh-case-item-offset) | |
790 (+ (ksh-current-indentation) | |
791 (if (null ksh-indent) | |
792 2 ksh-indent)))) | |
793 nil)) | |
794 )) | |
795 ;; | |
796 ;; handle then or do | |
797 ((progn | |
798 (save-excursion | |
799 (back-to-indentation) | |
800 (if (ksh-search-forward-sexp ksh-then-do-re fence-post) | |
801 (progn | |
793 (if (null ksh-indent) | 802 (if (null ksh-indent) |
794 2 ksh-indent) | 803 (+ (ksh-current-indentation) 1) |
795 ))) | 804 (+ (ksh-current-indentation) ksh-indent))) |
796 | 805 nil)))) |
797 ((re-search-forward ksh-then-do-re fence-post t) | 806 |
798 (if (null ksh-indent) | |
799 (progn | |
800 (goto-char (match-end 1)) | |
801 (+ (ksh-current-indentation) 1)) | |
802 (progn | |
803 (goto-char (match-beginning 1)) | |
804 (+ (ksh-current-indentation) ksh-indent)) | |
805 )) | |
806 | |
807 ((looking-at ksh-brace-re) | |
808 (+ (current-indentation) | |
809 (if (null ksh-indent) | |
810 2 ksh-indent) | |
811 )) | |
812 ;; | |
813 ;; Forces functions to first column | |
814 ((or (looking-at ksh-implicit-func-re) | |
815 (looking-at ksh-explicit-func-re)) | |
816 (if (looking-at ksh-func-brace-re) | |
817 (if (null ksh-indent) | |
818 2 ksh-indent) | |
819 ksh-brace-offset)) | |
820 | |
821 ;; | |
822 ;; Need to first detect the end of a case-item | |
823 ((looking-at ksh-case-item-end-re) | |
824 (end-of-line) | |
825 (+ (ksh-get-case-indent) ksh-case-item-offset)) | |
826 ;; | |
827 ;; Now detect first statement under a case item | |
828 ((ksh-looking-at-case-item) | |
829 (if (null ksh-case-indent) | |
830 (progn | |
831 (re-search-forward ksh-case-item-re fence-post t) | |
832 (goto-char (match-end 1)) | |
833 (+ (current-column) 1)) | |
834 (+ (current-indentation) ksh-case-indent))) | |
835 | |
836 ;; This is hosed when using current-column | |
837 ;; and there is a multi-command expression as the | |
838 ;; nester. | |
839 (t (current-indentation))) | |
840 ) | |
841 ));; excursion over | |
842 ;; | |
843 ;; Handle additional indentation constructs for this line | |
844 (cond ((ksh-looking-at-compound-list) | |
845 (+ nester-column ksh-group-offset)) | |
846 ((looking-at ksh-brace-re) | 807 ((looking-at ksh-brace-re) |
847 (+ nester-column ksh-brace-offset)) | 808 (+ (current-indentation) |
848 (t nester-column)) | 809 (if (null ksh-indent) |
849 );; Not a case-item | 810 2 ksh-indent) |
850 ) | 811 )) |
812 ;; | |
813 ;; Forces functions to first column | |
814 ((or (looking-at ksh-implicit-func-re) | |
815 (looking-at ksh-explicit-func-re)) | |
816 (if (looking-at ksh-func-brace-re) | |
817 (if (null ksh-indent) | |
818 2 ksh-indent) | |
819 ksh-brace-offset)) | |
820 | |
821 ;; | |
822 ;; Need to first detect the end of a case-item | |
823 ((looking-at ksh-case-item-end-re) | |
824 (end-of-line) | |
825 (+ (ksh-get-case-indent) ksh-case-item-offset)) | |
826 ;; | |
827 ;; Now detect first statement under a case item | |
828 ((ksh-looking-at-case-item) | |
829 (if (null ksh-case-indent) | |
830 (progn | |
831 (re-search-forward ksh-case-item-re fence-post t) | |
832 (goto-char (match-end 1)) | |
833 (+ (current-column) 1)) | |
834 (+ (current-indentation) ksh-case-indent))) | |
835 | |
836 ;; This is hosed when using current-column | |
837 ;; and there is a multi-command expression as the | |
838 ;; nester. | |
839 (t (current-indentation))) | |
840 ) | |
841 ));; excursion over | |
842 ;; | |
843 ;; Handle additional indentation constructs for this line | |
844 (cond ((ksh-looking-at-compound-list) | |
845 (+ nester-column ksh-group-offset)) | |
846 ((looking-at ksh-brace-re) | |
847 (+ nester-column ksh-brace-offset)) | |
848 (t nester-column)) | |
849 );; Not a case-item | |
850 ) | |
851 );;let | 851 );;let |
852 );; excursion | 852 );; excursion |
853 );; defun | 853 ) ;; defun |
854 | 854 |
855 (defun ksh-indent-command () | 855 (defun ksh-indent-command () |
856 "Indent current line relative to containing block and allow for | 856 "Indent current line relative to containing block and allow for |
857 ksh-tab-always-indent customization" | 857 ksh-tab-always-indent customization" |
858 (interactive) | 858 (interactive) |
903 ;; | 903 ;; |
904 ;; Position point on this line | 904 ;; Position point on this line |
905 (let* | 905 (let* |
906 ( | 906 ( |
907 (this-line-level (current-indentation)) | 907 (this-line-level (current-indentation)) |
908 (this-bol (save-excursion | 908 (this-bol (ksh-bol-point)) |
909 (beginning-of-line) | |
910 (point))) | |
911 (this-point (- (point) this-bol)) | 909 (this-point (- (point) this-bol)) |
912 ) | 910 ) |
913 (cond ((> this-line-level this-point);; point in initial white space | 911 (cond ((> this-line-level this-point);; point in initial white space |
914 (back-to-indentation)) | 912 (back-to-indentation)) |
915 (t nil) | 913 (t nil) |
957 the minibuffer" | 955 the minibuffer" |
958 (interactive) | 956 (interactive) |
959 (let (case-fold-search) | 957 (let (case-fold-search) |
960 (save-excursion | 958 (save-excursion |
961 (beginning-of-line) | 959 (beginning-of-line) |
960 (back-to-indentation) | |
962 (cond ((looking-at ksh-else-re) | 961 (cond ((looking-at ksh-else-re) |
963 (ksh-match-indent-level ksh-if-re ksh-fi-re)) | 962 (ksh-match-indent-level ksh-if-re ksh-fi-re)) |
964 ((looking-at ksh-elif-re) | 963 ((looking-at ksh-elif-re) |
965 (ksh-match-indent-level ksh-if-re ksh-fi-re)) | 964 (ksh-match-indent-level ksh-if-re ksh-fi-re)) |
966 ((looking-at ksh-fi-re) | 965 ((looking-at ksh-fi-re) |
979 (t nil) | 978 (t nil) |
980 );; cond | 979 );; cond |
981 ) | 980 ) |
982 )) | 981 )) |
983 | 982 |
984 (defun ksh-get-compound-level | 983 |
984 (defun ksh-search-backward-sexp (sexp-re fence-post) | |
985 (let | |
986 ((old-pnt (point)) | |
987 (sentinal nil) | |
988 ) | |
989 (while | |
990 (progn | |
991 (if (not sentinal) | |
992 (backward-sexp 1)) | |
993 (and (> (point) fence-post) | |
994 (not sentinal)) | |
995 ) | |
996 (if (looking-at sexp-re) | |
997 (save-excursion ;avoid comment foolage | |
998 (let ((key-fence (point))) | |
999 (beginning-of-line) | |
1000 (back-to-indentation) | |
1001 (while (and (ksh-search-forward-sexp sexp-re key-fence) | |
1002 (< (point) key-fence))) | |
1003 | |
1004 (if (= key-fence (point)) | |
1005 (setq sentinal t)) | |
1006 )) | |
1007 )) | |
1008 | |
1009 (if (< (point) fence-post) | |
1010 (progn (goto-char old-pnt) | |
1011 nil) | |
1012 t) | |
1013 )) | |
1014 | |
1015 (defun ksh-forward-sexp () | |
1016 "Special incantation to march over syntax expressions and | |
1017 avoid all sorts of nonsense" | |
1018 (if (char-equal ?< (char-syntax (char-after (point)))) | |
1019 (end-of-line) | |
1020 (if (char-equal ?. (char-syntax (char-after (point)))) | |
1021 (forward-char) | |
1022 (forward-sexp 1)) | |
1023 ) | |
1024 (if (eolp) | |
1025 (forward-line)) | |
1026 (skip-chars-forward ") \t") ;damn case | |
1027 ) | |
1028 | |
1029 (defun ksh-search-forward-sexp (sexp-re fence-post) | |
1030 "Search for an sexp. Return t on success with point at the | |
1031 beginning of the sexp. Return nil on failure and restoring point | |
1032 to it's original position" | |
1033 (let | |
1034 ((old-pnt (point)) | |
1035 ) | |
1036 (while (and (< (point) fence-post) | |
1037 (not (looking-at sexp-re))) | |
1038 (ksh-forward-sexp)) | |
1039 | |
1040 (if (> (point) fence-post) | |
1041 (progn (goto-char old-pnt) | |
1042 nil) | |
1043 t) | |
1044 )) | |
1045 | |
1046 | |
1047 (defun ksh-get-compound-level | |
985 (begin-re end-re anchor-point &optional balance-list) | 1048 (begin-re end-re anchor-point &optional balance-list) |
986 "Determine how much to indent this structure. Return a list (level line) | 1049 "Determine how much to indent this structure. Return a list (level line) |
987 of the matching compound command or nil if no match found." | 1050 of the matching compound command or nil if no match found." |
988 (let* | 1051 (let* |
989 (;; Locate the next compound begin keyword bounded by point-min | 1052 (;; Locate the next compound begin keyword bounded by point-min |
990 (match-point (if (re-search-backward begin-re (point-min) t) | 1053 (match-point |
991 (match-beginning 1) 0)) | 1054 (if (and (ksh-search-backward-sexp begin-re (point-min)) |
1055 (>= (point) (point-min)) | |
1056 ) | |
1057 (point) | |
1058 0)) | |
1059 | |
992 (nest-column (if (zerop match-point) | 1060 (nest-column (if (zerop match-point) |
993 1 | 1061 1 |
994 (progn | 1062 (progn |
995 (goto-char match-point) | 1063 (goto-char match-point) |
996 (ksh-current-indentation)))) | 1064 (ksh-current-indentation)))) |
1000 nil ;; graceful exit from recursion | 1068 nil ;; graceful exit from recursion |
1001 (progn | 1069 (progn |
1002 (if (nlistp balance-list) | 1070 (if (nlistp balance-list) |
1003 (setq balance-list (list))) | 1071 (setq balance-list (list))) |
1004 ;; Now search forward from matching start keyword for end keyword | 1072 ;; Now search forward from matching start keyword for end keyword |
1073 ;; which will locate interceding compound commands | |
1005 (while (and (consp nest-list) (zerop (cdr nest-list)) | 1074 (while (and (consp nest-list) (zerop (cdr nest-list)) |
1006 (re-search-forward end-re anchor-point t)) | 1075 (ksh-search-forward-sexp end-re anchor-point) |
1076 (> anchor-point (point)) | |
1077 ) | |
1007 (if (not (memq (point) balance-list)) | 1078 (if (not (memq (point) balance-list)) |
1008 (progn | 1079 (progn |
1009 (setq balance-list (cons (point) balance-list)) | 1080 (setq balance-list (cons (point) balance-list)) |
1010 (goto-char match-point) ;; beginning of compound cmd | 1081 (goto-char match-point) ;; beginning of compound cmd |
1011 (setq nest-list | 1082 (setq nest-list |
1012 (ksh-get-compound-level begin-re end-re | 1083 (ksh-get-compound-level begin-re end-re |
1013 anchor-point balance-list)) | 1084 anchor-point balance-list)) |
1014 ))) | 1085 ) |
1086 (ksh-forward-sexp) | |
1087 )) | |
1015 | 1088 |
1016 (cond ((consp nest-list) | 1089 (cond ((consp nest-list) |
1017 (if (zerop (cdr nest-list)) | 1090 (if (zerop (cdr nest-list)) |
1018 (progn | 1091 (progn |
1019 (goto-char match-point) | 1092 (goto-char match-point) |