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)