[svn] r5814: nemerle/trunk/misc/nemerle.el

kali svnadmin at nemerle.org
Wed Oct 12 14:32:04 CEST 2005


Log:
Improved handling of:
* if-like clauses with one-line blocks of code
* code in match clauses, if they contain braces-delimited blocks


Author: kali
Date: Wed Oct 12 14:32:03 2005
New Revision: 5814

Modified:
   nemerle/trunk/misc/nemerle.el

Modified: nemerle/trunk/misc/nemerle.el
==============================================================================
--- nemerle/trunk/misc/nemerle.el	(original)
+++ nemerle/trunk/misc/nemerle.el	Wed Oct 12 14:32:03 2005
@@ -155,8 +155,10 @@
   (let ((map (make-sparse-keymap)))
     (define-key map "\C-c\C-c" 'comment-region)
     (define-key map "|" 'nemerle-electric-bar)
-    (define-key map "}" 'nemerle-electric-brace)
+    (define-key map "{" 'nemerle-electric-brace-begin)
+    (define-key map "}" 'nemerle-electric-brace-end)
     (define-key map "*" 'nemerle-electric-star)
+    (define-key map "e" 'nemerle-electric-e)
     (setq nemerle-mode-map map)))
 
 (unless nemerle-font-lock-keywords
@@ -293,14 +295,21 @@
     (let ((end (point))
 	  (line 'none)
 	  (in-match-case nil)
+	  (depth 0)
 	  (at-end nil)
 	  (brace (nemerle-go-up-one-level)))
       (if (not (eq brace ?{))
 	  nil
 	(beginning-of-line)
 	(while (and (not at-end) (<= (point) end))
+	  (cond ((looking-at ".*{[^}]*$")
+		 (setq depth (+ depth 1)))
+		((looking-at ".*}[^{]*$")
+		 (setq depth (- depth 1)))
+		(t
+		 nil))
 	  (setq line (nemerle-analyze-line))
-	  (if (eq line 'match-case)
+	  (if (and (eq line 'match-case) (eq depth 1))
 	      (setq in-match-case t))
 	  (if (> (forward-line 1) 0)
 	      (setq at-end t)))
@@ -324,10 +333,14 @@
 	     'comment))
 	  ((nemerle-in-string)
 	   'in-string)
+	  ((looking-at "[ \t]*{")
+	   'begin-brace)
 	  ((looking-at "[ \t]*}")
 	   'end-brace)
 	  ((looking-at "[ \t]*|")
 	   'match-case)
+	  ((looking-at "[ \t]*else[ \t]*")
+	   'else-clause)
 	  (t
 	   'none))))
 
@@ -335,21 +348,90 @@
 (defun nemerle-analyze-block (end result)
   "Analyze the block from current point position until END.  Return
 the relative offset + result for the block."
-  (beginning-of-line)
-  (let ((line 'none)
-	(in-match-case nil)
-	(at-end nil))
-    (while (and (not at-end) (<= (point) end))
-      (setq line (nemerle-analyze-line))
-      (cond ((eq line 'match-case)
-	     (setq in-match-case t))
-	    (t
-	     nil))
-      (if (> (forward-line 1) 0)
-	  (setq at-end t)))
-    (if in-match-case
+  (goto-char end)
+  (if (nemerle-in-match)
 	(setq result (+ result nemerle-match-case-offset)))
-    result))
+  result)
+
+
+;; Go backwards, skipping comments, but no further than begin.
+;; After calling this  function you end up at most at the beginning
+;; of the line containing begin.
+(defun nemerle-go-backwards (begin)
+  ;; checks if currrent line is a comment line
+  ;; such situation will be noticed either by nemerle in comment in case
+  ;; of being in the middle of multi line comment or two regexps checking
+  ;; for the beginning of a comment.
+  (defun is-comment-line ()
+    (or (looking-at "[ \t]*//")	(looking-at "[ \t]*/\\*") (nemerle-in-comment)))
+
+  (while (and (eq (forward-line -1) 0) (<= begin (point)) (is-comment-line))
+    nil))
+ 
+
+(defun nemerle-check-if (end line offset)
+  "Checks if we have a case of if/else/whatever with one-line body. In such
+case braces may be missing and then syntax parser won't indicate the need to
+nest next line. This function will."
+  ;; check previous line for the if case and return offset
+  (let ((begin (point))
+	(add_offset 0) ; additional offset we could add
+	(done nil))
+    (unless (eq line 'begin-brace) ; don't indent begin-brace any more
+      (setq add_offset nemerle-basic-offset))
+    
+    (goto-char end)
+    (nemerle-go-backwards begin)
+    (if (> begin (point)) ; gone to far
+	(setq done t))
+    (goto-char (max (+ begin 1) (point)))
+    (let ((here (point))
+	  (type 'none))
+       (setq type (cond
+		   ((looking-at "[ \t]*\\(if\\|for\\|foreach\\|while\\|when\\|unless\\)[ \t]*(")
+		    'if)
+		   ((looking-at "[ \t]*else[ \t]*")
+		    'else)
+		   (t
+		    'none)))
+       (goto-char begin)
+       (if (eq type 'else)
+	   ;; skip to corresponding if - we should have same indentation
+	   (setq here (nemerle-find-if here)))
+       (if (eq type 'none)
+	   offset
+	 ;; we have the if-case, so increase offset and check another line
+	 ;; in case of nested if-cases
+	 (setq offset (+ offset add_offset))
+	 (if done
+	     offset
+	   (nemerle-check-if here 'none offset))))))
+	 
+
+(defun nemerle-find-if (end)
+  "Find if clause corresponding to else clause at position END. Return
+its position or END if no appropriate clause was found."
+  (let ((begin (point))
+	(depth 1)
+	(retval nil)
+	(too-far nil))
+    ;; depth is number of unmatched else's. We start with value of
+    ;; of 1 - the else line at end, and proceed until it reaches 0
+    (goto-char end)
+    (while (and (not (eq depth 0)) (not too-far))
+      (nemerle-go-backwards begin)
+      (if (> begin (point)) ;; oops - to far
+	  (setq too-far t))
+      (goto-char (max (+ 1 begin) (point)))
+      (if (looking-at "[ \t]*else[ \t]*")
+	  (setq depth (+ depth 1))
+	(if (looking-at "[ \t]*if[ \t]*(")
+	    (setq depth (- depth 1)))))
+    (if (eq depth 0)
+	(setq retval (point))
+      (setq retval end))
+    (goto-char begin)
+    retval))
 
 
 (defun nemerle-get-offset (end line)
@@ -361,15 +443,22 @@
 	((eq line 'comment)
 	 (nemerle-analyze-block end 2))
 	((eq line 'star-comment)
-	 (nemerle-analyze-block end 1))
+	 ;; handle star comments inside if-clause without braces
+	 (nemerle-analyze-block end (+ 1 (nemerle-check-if end line 0))))
 	((eq line 'match-case)
 	 (nemerle-analyze-block end (- nemerle-match-case-offset)))
+	((eq line 'else-clause)
+	 ;; handle proper indentation of else clause
+	 (nemerle-analyze-block end (nemerle-check-if
+				     (nemerle-find-if end)
+				     line 0)))
 	(t
-	 (nemerle-analyze-block end 0))))
+	 ;; handle if-clause without braces
+	 (nemerle-analyze-block end (nemerle-check-if end line 0)))))
 
 
 (defun nemerle-get-nested (end line)
-  "Retrun the relative offset for the line LINE nested in the block
+  "Return the relative offset for the line LINE nested in the block
 of code.  Analyze code from the current point position until END."
   (if (eq line 'end-brace)
       0
@@ -436,18 +525,48 @@
     (self-insert-command 1)))
 	
 
-(defun nemerle-electric-brace (arg)
+(defun nemerle-electric-e (arg)
+  "Insert letter e and force reindent if it's else-clause."
+  (interactive "p")
+  (self-insert-command (or arg 1))
+   (save-excursion
+     (beginning-of-line)
+     (cond ((looking-at "[ \t]*else[ \t]*")
+ 	   (let ((level (nemerle-calculate-indentation-of-line 'else-clause)))
+ 	     (nemerle-indent-to level))))))
+
+
+;; Common part of brace handling. Functions for specific brace (begin, end)
+;; need just to pass appropriate MEANING param.
+(defun nemerle-electric-brace (arg meaning)
   "Insert a brace.
 
-Also, the line is re-indented unless a numeric ARG is supplied."
-  (interactive "p")
+Also, the line is re-indented unless a numeric ARG is supplied.
+MEANING is the symbol denoting syntax meaning of current line:
+begin-brace or end-brace."
   (if (or (and arg (> arg 1)) (not (nemerle-on-empty-line)))
       (self-insert-command (or arg 1))
-    (let ((level (nemerle-calculate-indentation-of-line 'end-brace)))
+    (let ((level (nemerle-calculate-indentation-of-line meaning)))
       (nemerle-indent-to level))
     (self-insert-command 1)))
 
 
+(defun nemerle-electric-brace-begin (arg)
+  "Insert a brace.
+
+Also, the line is re-indented unless a numeric ARG is supplied."
+  (interactive "p")
+  (nemerle-electric-brace arg 'begin-brace))
+
+
+(defun nemerle-electric-brace-end (arg)
+  "Insert a brace.
+
+Also, the line is re-indented unless a numeric ARG is supplied."
+  (interactive "p")
+  (nemerle-electric-brace arg 'end-brace))
+
+
 (defun nemerle-electric-star (arg)
   "Insert an asterisk.
 



More information about the svn mailing list