Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'master' of defprotocol.org:/home/git/emacsd

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
  • Loading branch information...
commit 80bc067da8069ab45c4cf3e380256722547cc2b9 2 parents 1200226 + 07afaff
Michael Klishin authored
166  bundles/fsharp/fsharp-font.el
... ...
@@ -0,0 +1,166 @@
  1
+;(***********************************************************************)
  2
+;(*                                                                     *)
  3
+;(*                           Objective Caml                            *)
  4
+;(*                                                                     *)
  5
+;(*                Jacques Garrigue and Ian T Zimmerman                 *)
  6
+;(*                                                                     *)
  7
+;(*  Copyright 1997 Institut National de Recherche en Informatique et   *)
  8
+;(*  en Automatique.  All rights reserved.  This file is distributed    *)
  9
+;(*  under the terms of the GNU General Public License.                 *)
  10
+;(*                                                                     *)
  11
+;(***********************************************************************)
  12
+
  13
+;(* $Id: fsharp-font.el,v 1.19 2004/08/20 17:04:35 doligez Exp $ *)
  14
+
  15
+;; useful colors
  16
+
  17
+(cond
  18
+ ((x-display-color-p)
  19
+  (require 'font-lock)
  20
+  (cond
  21
+   ((not (boundp 'font-lock-type-face))
  22
+    ;; make the necessary faces
  23
+    (make-face 'Firebrick)
  24
+    (set-face-foreground 'Firebrick "firebrick")
  25
+    (make-face 'RosyBrown)
  26
+    (set-face-foreground 'RosyBrown "RosyBrown")
  27
+    (make-face 'Purple)
  28
+    (set-face-foreground 'Purple "Purple")
  29
+    (make-face 'MidnightBlue)
  30
+    (set-face-foreground 'MidnightBlue "MidnightBlue")
  31
+    (make-face 'DarkGoldenRod)
  32
+    (set-face-foreground 'DarkGoldenRod "DarkGoldenRod")
  33
+    (make-face 'DarkOliveGreen)
  34
+    (set-face-foreground 'DarkOliveGreen "DarkOliveGreen4")
  35
+    (make-face 'CadetBlue)
  36
+    (set-face-foreground 'CadetBlue "CadetBlue")
  37
+    ; assign them as standard faces
  38
+    (setq font-lock-comment-face 'Firebrick)
  39
+    (setq font-lock-string-face 'RosyBrown)
  40
+    (setq font-lock-keyword-face 'Purple)
  41
+    (setq font-lock-function-name-face 'MidnightBlue)
  42
+    (setq font-lock-variable-name-face 'DarkGoldenRod)
  43
+    (setq font-lock-type-face 'DarkOliveGreen)
  44
+    (setq font-lock-reference-face 'CadetBlue)))
  45
+  ; extra faces for documention
  46
+  (make-face 'Stop)
  47
+  (set-face-foreground 'Stop "White")
  48
+  (set-face-background 'Stop "Red")
  49
+  (make-face 'Doc)
  50
+  (set-face-foreground 'Doc "Red")
  51
+  (setq font-lock-stop-face 'Stop)
  52
+  (setq font-lock-doccomment-face 'Doc)
  53
+))
  54
+
  55
+
  56
+(defconst fsharp-font-lock-keywords
  57
+  (list
  58
+;stop special comments
  59
+   '("\\(^\\|[^\"]\\)\\((\\*\\*/\\*\\*)\\)"
  60
+     2 font-lock-stop-face)
  61
+;doccomments
  62
+   '("\\(^\\|[^\"]\\)\\((\\*\\*[^*]*\\([^)*][^*]*\\*+\\)*)\\)"
  63
+     2 font-lock-doccomment-face)
  64
+;comments
  65
+   '("\\(^\\|[^\"]\\)\\((\\*[^*]*\\*+\\([^)*][^*]*\\*+\\)*)\\)"
  66
+     2 font-lock-comment-face)
  67
+
  68
+;;  '("(\\*IF-OCAML\\([^)*][^*]*\\*+\\)+ENDIF-OCAML\\*)"
  69
+;;    2 font-lock-comment-face)
  70
+
  71
+;;   '("\\(^\\|[^\"]\\)\\((\\*[^F]\\([^)*][^*]*\\*+\\)+)\\)"
  72
+;;     . font-lock-comment-face)
  73
+;  '("(\\*.*\\*)\\|(\\*.*\n.*\\*)"
  74
+;    . font-lock-comment-face)
  75
+
  76
+
  77
+;character literals
  78
+   (cons (concat "'\\(\\\\\\([ntbr'\\]\\|"
  79
+                 "[0-9][0-9][0-9]\\)\\|.\\)'"
  80
+                 "\\|\"[^\"\\]*\\(\\\\\\(.\\|\n\\)[^\"\\]*\\)*\"")
  81
+         'font-lock-string-face)
  82
+
  83
+  '("//.*" . font-lock-comment-face)
  84
+
  85
+;modules and constructors
  86
+   '("`?\\<[A-Z][A-Za-z0-9_']*\\>" . font-lock-function-name-face)
  87
+;definition
  88
+
  89
+   (cons (concat "\\(\\<"
  90
+                 (mapconcat 'identity
  91
+                            '(
  92
+                              ;; F# keywords
  93
+                              "abstract" "and" "as" "assert" "base" "begin"
  94
+                              "class" "default" "delegate" "do" "done" "downcast"
  95
+                              "downto" "elif" "else" "end" "exception" "extern"
  96
+                              "false" "finally" "for" "fun" "function" "global"
  97
+                              "if" "in" "inherit" "inline" "interface" "internal"
  98
+                              "lazy" "let" "match" "member" "module" "mutable"
  99
+                              "namespace" "new" "null" "of" "open" "or" "override"
  100
+                              "private" "public" "rec" "return" "sig" "static"
  101
+                              "struct" "then" "to" "true" "try" "type" "upcast"
  102
+                              "use" "val" "void" "when" "while" "with" "yield"
  103
+
  104
+                              ;; F# reserved words for future use
  105
+                              "atomic" "break" "checked" "component" "const"
  106
+                              "constraint" "constructor" "continue" "eager"
  107
+                              "fixed" "fori" "functor" "include" "measure"
  108
+                              "method" "mixin" "object" "parallel" "params"
  109
+                              "process" "protected" "pure" "recursive" "sealed"
  110
+                              "tailcall" "trait" "virtual" "volatile"
  111
+                              )
  112
+                            "\\>\\|\\<")
  113
+                 "\\>\\)")
  114
+         'font-lock-type-face)
  115
+
  116
+;blocking
  117
+;;    '("\\<\\(begin\\|end\\|module\\|namespace\\|object\\|sig\\|struct\\)\\>"
  118
+;;      . font-lock-keyword-face)
  119
+;control
  120
+   (cons (concat
  121
+          "\\<\\(asr\\|false\\|land\\|lor\\|lsl\\|lsr\\|lxor"
  122
+          "\\|mod\\|new\\|null\\|object\\|or\\|sig\\|true\\)\\>"
  123
+          "\\|\|\\|->\\|&\\|#")
  124
+         'font-lock-reference-face)
  125
+;labels (and open)
  126
+   '("\\<\\(assert\\|open\\|include\\|module\\|namespace\\|extern\\|void\\)\\>\\|[~?][ (]*[a-z][a-zA-Z0-9_']*"
  127
+     . font-lock-variable-name-face)))
  128
+
  129
+(defconst inferior-fsharp-font-lock-keywords
  130
+  (append
  131
+   (list
  132
+;inferior
  133
+    '("^[#-]" . font-lock-comment-face)
  134
+   '("^>" . font-lock-variable-name-face))
  135
+   fsharp-font-lock-keywords))
  136
+
  137
+;; font-lock commands are similar for fsharp-mode and inferior-fsharp-mode
  138
+(add-hook 'fsharp-mode-hook
  139
+      '(lambda ()
  140
+         (cond
  141
+          ((fboundp 'global-font-lock-mode)
  142
+           (make-local-variable 'font-lock-defaults)
  143
+           (setq font-lock-defaults
  144
+                 '(fsharp-font-lock-keywords nil nil ((?' . "w") (?_ . "w")))))
  145
+          (t
  146
+           (setq font-lock-keywords fsharp-font-lock-keywords)))
  147
+         (make-local-variable 'font-lock-keywords-only)
  148
+         (setq font-lock-keywords-only t)
  149
+         (font-lock-mode 1)))
  150
+
  151
+(defun inferior-fsharp-mode-font-hook ()
  152
+  (cond
  153
+   ((fboundp 'global-font-lock-mode)
  154
+    (make-local-variable 'font-lock-defaults)
  155
+    (setq font-lock-defaults
  156
+          '(inferior-fsharp-font-lock-keywords
  157
+            nil nil ((?' . "w") (?_ . "w")))))
  158
+   (t
  159
+    (setq font-lock-keywords inferior-fsharp-font-lock-keywords)))
  160
+  (make-local-variable 'font-lock-keywords-only)
  161
+  (setq font-lock-keywords-only t)
  162
+  (font-lock-mode 1))
  163
+
  164
+(add-hook 'inferior-fsharp-mode-hooks 'inferior-fsharp-mode-font-hook)
  165
+
  166
+(provide 'fsharp-font)
1,636  bundles/fsharp/fsharp-indent.el
... ...
@@ -0,0 +1,1636 @@
  1
+;; Indentation rules for F#
  2
+;; Based on python-mode
  3
+
  4
+(require 'comint)
  5
+(require 'custom)
  6
+(require 'cl)
  7
+(require 'compile)
  8
+
  9
+
  10
+;; user definable variables
  11
+;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  12
+
  13
+(defgroup fsharp nil
  14
+  "Support for the Fsharp programming language, <http://www.fsharp.net/>"
  15
+  :group 'languages
  16
+  :prefix "fsharp-")
  17
+
  18
+(defcustom fsharp-tab-always-indent t
  19
+  "*Non-nil means TAB in Fsharp mode should always reindent the current line,
  20
+regardless of where in the line point is when the TAB command is used."
  21
+  :type 'boolean
  22
+  :group 'fsharp)
  23
+
  24
+(defcustom fsharp-indent-offset 4
  25
+  "*Amount of offset per level of indentation.
  26
+`\\[fsharp-guess-indent-offset]' can usually guess a good value when
  27
+you're editing someone else's Fsharp code."
  28
+  :type 'integer
  29
+  :group 'fsharp)
  30
+
  31
+(defcustom fsharp-continuation-offset 2
  32
+  "*Additional amount of offset to give for some continuation lines.
  33
+Continuation lines are those that immediately follow a backslash
  34
+terminated line.  Only those continuation lines for a block opening
  35
+statement are given this extra offset."
  36
+  :type 'integer
  37
+  :group 'fsharp)
  38
+
  39
+(defcustom fsharp-smart-indentation t
  40
+  "*Should `fsharp-mode' try to automagically set some indentation variables?
  41
+When this variable is non-nil, two things happen when a buffer is set
  42
+to `fsharp-mode':
  43
+
  44
+    1. `fsharp-indent-offset' is guessed from existing code in the buffer.
  45
+       Only guessed values between 2 and 8 are considered.  If a valid
  46
+       guess can't be made (perhaps because you are visiting a new
  47
+       file), then the value in `fsharp-indent-offset' is used.
  48
+
  49
+    2. `indent-tabs-mode' is turned off if `fsharp-indent-offset' does not
  50
+       equal `tab-width' (`indent-tabs-mode' is never turned on by
  51
+       Fsharp mode).  This means that for newly written code, tabs are
  52
+       only inserted in indentation if one tab is one indentation
  53
+       level, otherwise only spaces are used.
  54
+
  55
+Note that both these settings occur *after* `fsharp-mode-hook' is run,
  56
+so if you want to defeat the automagic configuration, you must also
  57
+set `fsharp-smart-indentation' to nil in your `fsharp-mode-hook'."
  58
+  :type 'boolean
  59
+  :group 'fsharp)
  60
+
  61
+(defcustom fsharp-honor-comment-indentation t
  62
+  "*Controls how comment lines influence subsequent indentation.
  63
+
  64
+When nil, all comment lines are skipped for indentation purposes, and
  65
+if possible, a faster algorithm is used (i.e. X/Emacs 19 and beyond).
  66
+
  67
+When t, lines that begin with a single `//' are a hint to subsequent
  68
+line indentation.  If the previous line is such a comment line (as
  69
+opposed to one that starts with `fsharp-block-comment-prefix'), then its
  70
+indentation is used as a hint for this line's indentation.  Lines that
  71
+begin with `fsharp-block-comment-prefix' are ignored for indentation
  72
+purposes.
  73
+
  74
+When not nil or t, comment lines that begin with a single `//' are used
  75
+as indentation hints, unless the comment character is in column zero."
  76
+  :type '(choice
  77
+	  (const :tag "Skip all comment lines (fast)" nil)
  78
+	  (const :tag "Single // `sets' indentation for next line" t)
  79
+	  (const :tag "Single // `sets' indentation except at column zero"
  80
+		 other)
  81
+	  )
  82
+  :group 'fsharp)
  83
+
  84
+(defcustom fsharp-backspace-function 'backward-delete-char-untabify
  85
+  "*Function called by `fsharp-electric-backspace' when deleting backwards."
  86
+  :type 'function
  87
+  :group 'fsharp)
  88
+
  89
+(defcustom fsharp-delete-function 'delete-char
  90
+  "*Function called by `fsharp-electric-delete' when deleting forwards."
  91
+  :type 'function
  92
+  :group 'fsharp)
  93
+
  94
+
  95
+;; Constants
  96
+
  97
+(defconst fsharp-stringlit-re
  98
+  (concat
  99
+   ;; These fail if backslash-quote ends the string (not worth
  100
+   ;; fixing?).  They precede the short versions so that the first two
  101
+   ;; quotes don't look like an empty short string.
  102
+   ;;
  103
+   ;; (maybe raw), long single quoted triple quoted strings (SQTQ),
  104
+   ;; with potential embedded single quotes
  105
+   "[rR]?'''[^']*\\(\\('[^']\\|''[^']\\)[^']*\\)*'''"
  106
+   "\\|"
  107
+   ;; (maybe raw), long double quoted triple quoted strings (DQTQ),
  108
+   ;; with potential embedded double quotes
  109
+   "[rR]?\"\"\"[^\"]*\\(\\(\"[^\"]\\|\"\"[^\"]\\)[^\"]*\\)*\"\"\""
  110
+   "\\|"
  111
+   "[rR]?'\\([^'\n\\]\\|\\\\.\\)*'"	; single-quoted
  112
+   "\\|"				; or
  113
+   "[rR]?\"\\([^\"\n\\]\\|\\\\.\\)*\""	; double-quoted
  114
+   )
  115
+  "Regular expression matching a Fsharp string literal.")
  116
+
  117
+(defconst fsharp-continued-re
  118
+  ;; This is tricky because a trailing backslash does not mean
  119
+  ;; continuation if it's in a comment
  120
+;;   (concat
  121
+;;    "\\(" "[^#'\"\n\\]" "\\|" fsharp-stringlit-re "\\)*"
  122
+;;    "\\\\$")
  123
+;;   "Regular expression matching Fsharp backslash continuation lines.")
  124
+  (concat ".*\\(" (mapconcat 'identity
  125
+			   '("+" "-" "*" "/")
  126
+			   "\\|")
  127
+	  "\\)$")
  128
+  "Regular expression matching unterminated expressions.")
  129
+
  130
+
  131
+;(defconst fsharp-blank-or-comment-re "[ \t]*\\($\\|#\\)"
  132
+(defconst fsharp-blank-or-comment-re "[ \t]*\\(//.*\\)?"
  133
+  "Regular expression matching a blank or comment line.")
  134
+
  135
+(defconst fsharp-outdent-re
  136
+  (concat "\\(" (mapconcat 'identity
  137
+			   '("else"
  138
+			     "with"
  139
+                             "finally"
  140
+                             "end"
  141
+                             "done"
  142
+			     "elif")
  143
+			   "\\|")
  144
+	  "\\)")
  145
+  "Regular expression matching statements to be dedented one level.")
  146
+
  147
+(defconst fsharp-block-closing-keywords-re
  148
+;  "\\(return\\|raise\\|break\\|continue\\|pass\\)"
  149
+  "\\(end\\|done\\|raise\\|failwith\\|failwithf\\|rethrow\\|exit\\)"
  150
+  "Regular expression matching keywords which typically close a block.")
  151
+
  152
+
  153
+(defconst fsharp-no-outdent-re
  154
+  (concat
  155
+   "\\("
  156
+   (mapconcat 'identity
  157
+	      (list "try"
  158
+		    "while\\s +.*"
  159
+		    "for\\s +.*"
  160
+		    "then"
  161
+		    (concat fsharp-block-closing-keywords-re "[ \t\n]")
  162
+		    )
  163
+	      "\\|")
  164
+	  "\\)")
  165
+  "Regular expression matching lines not to dedent after.")
  166
+
  167
+
  168
+(defconst fsharp-block-opening-re
  169
+  (concat "\\(" (mapconcat 'identity
  170
+			   '("then"
  171
+                          "else"
  172
+			     "with"
  173
+                          "finally"
  174
+                          "class"
  175
+                          "struct"
  176
+			     "="        ; for example: let f x =
  177
+                          "->"
  178
+                          "do"
  179
+                          "try"
  180
+                          "function")
  181
+			   "\\|")
  182
+	  "\\)")
  183
+  "Regular expression matching expressions which begin a block")
  184
+
  185
+
  186
+;; Major mode boilerplate
  187
+
  188
+;; define a mode-specific abbrev table for those who use such things
  189
+(defvar fsharp-mode-abbrev-table nil
  190
+  "Abbrev table in use in `fsharp-mode' buffers.")
  191
+(define-abbrev-table 'fsharp-mode-abbrev-table nil)
  192
+
  193
+
  194
+
  195
+;; Utilities
  196
+(defmacro fsharp-safe (&rest body)
  197
+  "Safely execute BODY, return nil if an error occurred."
  198
+  `(condition-case nil
  199
+       (progn ,@ body)
  200
+     (error nil)))
  201
+
  202
+
  203
+(defsubst fsharp-keep-region-active ()
  204
+  "Keep the region active in XEmacs."
  205
+  ;; Ignore byte-compiler warnings you might see.  Also note that
  206
+  ;; FSF's Emacs 19 does it differently; its policy doesn't require us
  207
+  ;; to take explicit action.
  208
+  (and (boundp 'zmacs-region-stays)
  209
+       (setq zmacs-region-stays t)))
  210
+
  211
+(defsubst fsharp-point (position)
  212
+  "Returns the value of point at certain commonly referenced POSITIONs.
  213
+POSITION can be one of the following symbols:
  214
+
  215
+  bol  -- beginning of line
  216
+  eol  -- end of line
  217
+  bod  -- beginning of def or class
  218
+  eod  -- end of def or class
  219
+  bob  -- beginning of buffer
  220
+  eob  -- end of buffer
  221
+  boi  -- back to indentation
  222
+  bos  -- beginning of statement
  223
+
  224
+This function does not modify point or mark."
  225
+  (let ((here (point)))
  226
+    (cond
  227
+     ((eq position 'bol) (beginning-of-line))
  228
+     ((eq position 'eol) (end-of-line))
  229
+     ((eq position 'bod) (fsharp-beginning-of-def-or-class 'either))
  230
+     ((eq position 'eod) (fsharp-end-of-def-or-class 'either))
  231
+     ;; Kind of funny, I know, but useful for fsharp-up-exception.
  232
+     ((eq position 'bob) (beginning-of-buffer))
  233
+     ((eq position 'eob) (end-of-buffer))
  234
+     ((eq position 'boi) (back-to-indentation))
  235
+     ((eq position 'bos) (fsharp-goto-initial-line))
  236
+     (t (error "Unknown buffer position requested: %s" position))
  237
+     )
  238
+    (prog1
  239
+	(point)
  240
+      (goto-char here))))
  241
+
  242
+(defun fsharp-in-literal (&optional lim)
  243
+  "Return non-nil if point is in a Fsharp literal (a comment or string).
  244
+Optional argument LIM indicates the beginning of the containing form,
  245
+i.e. the limit on how far back to scan."
  246
+  ;; This is the version used for non-XEmacs, which has a nicer
  247
+  ;; interface.
  248
+  ;;
  249
+  ;; WARNING: Watch out for infinite recursion.
  250
+  (let* ((lim (or lim (fsharp-point 'bod)))
  251
+	 (state (parse-partial-sexp lim (point))))
  252
+    (cond
  253
+     ((nth 3 state) 'string)
  254
+     ((nth 4 state) 'comment)
  255
+     (t nil))))
  256
+
  257
+;; XEmacs has a built-in function that should make this much quicker.
  258
+;; In this case, lim is ignored
  259
+(defun fsharp-fast-in-literal (&optional lim)
  260
+  "Fast version of `fsharp-in-literal', used only by XEmacs.
  261
+Optional LIM is ignored."
  262
+  ;; don't have to worry about context == 'block-comment
  263
+  (buffer-syntactic-context))
  264
+
  265
+(if (fboundp 'buffer-syntactic-context)
  266
+    (defalias 'fsharp-in-literal 'fsharp-fast-in-literal))
  267
+
  268
+
  269
+
  270
+
  271
+;; electric characters
  272
+(defun fsharp-outdent-p ()
  273
+  "Returns non-nil if the current line should dedent one level."
  274
+  (save-excursion
  275
+    (progn (back-to-indentation)
  276
+           (looking-at fsharp-outdent-re))
  277
+))
  278
+
  279
+;;     (and (progn (back-to-indentation)
  280
+;; 		(looking-at fsharp-outdent-re))
  281
+;; 	 ;; short circuit infloop on illegal construct
  282
+;; 	 (not (bobp))
  283
+;; 	 (progn (forward-line -1)
  284
+;; 		(fsharp-goto-initial-line)
  285
+;; 		(back-to-indentation)
  286
+;; 		(while (or (looking-at fsharp-blank-or-comment-re)
  287
+;; 			   (bobp))
  288
+;; 		  (backward-to-indentation 1))
  289
+;; 		(not (looking-at fsharp-no-outdent-re)))
  290
+;; 	 )))
  291
+
  292
+(defun fsharp-electric-colon (arg)
  293
+  "Insert a colon.
  294
+In certain cases the line is dedented appropriately.  If a numeric
  295
+argument ARG is provided, that many colons are inserted
  296
+non-electrically.  Electric behavior is inhibited inside a string or
  297
+comment."
  298
+  (interactive "*P")
  299
+  (self-insert-command (prefix-numeric-value arg))
  300
+  ;; are we in a string or comment?
  301
+  (if (save-excursion
  302
+	(let ((pps (parse-partial-sexp (save-excursion
  303
+					 (fsharp-beginning-of-def-or-class)
  304
+					 (point))
  305
+				       (point))))
  306
+	  (not (or (nth 3 pps) (nth 4 pps)))))
  307
+      (save-excursion
  308
+	(let ((here (point))
  309
+	      (outdent 0)
  310
+	      (indent (fsharp-compute-indentation t)))
  311
+	  (if (and (not arg)
  312
+		   (fsharp-outdent-p)
  313
+		   (= indent (save-excursion
  314
+			       (fsharp-next-statement -1)
  315
+			       (fsharp-compute-indentation t)))
  316
+		   )
  317
+	      (setq outdent fsharp-indent-offset))
  318
+	  ;; Don't indent, only dedent.  This assumes that any lines
  319
+	  ;; that are already dedented relative to
  320
+	  ;; fsharp-compute-indentation were put there on purpose.  It's
  321
+	  ;; highly annoying to have `:' indent for you.  Use TAB, C-c
  322
+	  ;; C-l or C-c C-r to adjust.  TBD: Is there a better way to
  323
+	  ;; determine this???
  324
+	  (if (< (current-indentation) indent) nil
  325
+	    (goto-char here)
  326
+	    (beginning-of-line)
  327
+	    (delete-horizontal-space)
  328
+	    (indent-to (- indent outdent))
  329
+	    )))))
  330
+
  331
+
  332
+
  333
+;; Electric deletion
  334
+(defun fsharp-electric-backspace (arg)
  335
+  "Delete preceding character or levels of indentation.
  336
+Deletion is performed by calling the function in `fsharp-backspace-function'
  337
+with a single argument (the number of characters to delete).
  338
+
  339
+If point is at the leftmost column, delete the preceding newline.
  340
+
  341
+Otherwise, if point is at the leftmost non-whitespace character of a
  342
+line that is neither a continuation line nor a non-indenting comment
  343
+line, or if point is at the end of a blank line, this command reduces
  344
+the indentation to match that of the line that opened the current
  345
+block of code.  The line that opened the block is displayed in the
  346
+echo area to help you keep track of where you are.  With
  347
+\\[universal-argument] dedents that many blocks (but not past column
  348
+zero).
  349
+
  350
+Otherwise the preceding character is deleted, converting a tab to
  351
+spaces if needed so that only a single column position is deleted.
  352
+\\[universal-argument] specifies how many characters to delete;
  353
+default is 1.
  354
+
  355
+When used programmatically, argument ARG specifies the number of
  356
+blocks to dedent, or the number of characters to delete, as indicated
  357
+above."
  358
+  (interactive "*p")
  359
+  (if (or (/= (current-indentation) (current-column))
  360
+	  (bolp)
  361
+	  (fsharp-continuation-line-p)
  362
+;	  (not fsharp-honor-comment-indentation)
  363
+;	  (looking-at "#[^ \t\n]")	; non-indenting #
  364
+	  )
  365
+      (funcall fsharp-backspace-function arg)
  366
+    ;; else indent the same as the colon line that opened the block
  367
+    ;; force non-blank so fsharp-goto-block-up doesn't ignore it
  368
+    (insert-char ?* 1)
  369
+    (backward-char)
  370
+    (let ((base-indent 0)		; indentation of base line
  371
+	  (base-text "")		; and text of base line
  372
+	  (base-found-p nil))
  373
+      (save-excursion
  374
+	(while (< 0 arg)
  375
+	  (condition-case nil		; in case no enclosing block
  376
+	      (progn
  377
+		(fsharp-goto-block-up 'no-mark)
  378
+		(setq base-indent (current-indentation)
  379
+		      base-text   (fsharp-suck-up-leading-text)
  380
+		      base-found-p t))
  381
+	    (error nil))
  382
+	  (setq arg (1- arg))))
  383
+      (delete-char 1)			; toss the dummy character
  384
+      (delete-horizontal-space)
  385
+      (indent-to base-indent)
  386
+      (if base-found-p
  387
+	  (message "Closes block: %s" base-text)))))
  388
+
  389
+
  390
+(defun fsharp-electric-delete (arg)
  391
+  "Delete preceding or following character or levels of whitespace.
  392
+
  393
+The behavior of this function depends on the variable
  394
+`delete-key-deletes-forward'.  If this variable is nil (or does not
  395
+exist, as in older Emacsen and non-XEmacs versions), then this
  396
+function behaves identically to \\[c-electric-backspace].
  397
+
  398
+If `delete-key-deletes-forward' is non-nil and is supported in your
  399
+Emacs, then deletion occurs in the forward direction, by calling the
  400
+function in `fsharp-delete-function'.
  401
+
  402
+\\[universal-argument] (programmatically, argument ARG) specifies the
  403
+number of characters to delete (default is 1)."
  404
+  (interactive "*p")
  405
+ (funcall fsharp-delete-function arg))
  406
+;;   (if (or (and (fboundp 'delete-forward-p) ;XEmacs 21
  407
+;; 	       (delete-forward-p))
  408
+;; 	  (and (boundp 'delete-key-deletes-forward) ;XEmacs 20
  409
+;; 	       delete-key-deletes-forward))
  410
+;;       (funcall fsharp-delete-function arg)
  411
+;;     (fsharp-electric-backspace arg)))
  412
+
  413
+;; required for pending-del and delsel modes
  414
+(put 'fsharp-electric-colon 'delete-selection t) ;delsel
  415
+(put 'fsharp-electric-colon 'pending-delete   t) ;pending-del
  416
+(put 'fsharp-electric-backspace 'delete-selection 'supersede) ;delsel
  417
+(put 'fsharp-electric-backspace 'pending-delete   'supersede) ;pending-del
  418
+(put 'fsharp-electric-delete    'delete-selection 'supersede) ;delsel
  419
+(put 'fsharp-electric-delete    'pending-delete   'supersede) ;pending-del
  420
+
  421
+
  422
+
  423
+(defun fsharp-indent-line (&optional arg)
  424
+  "Fix the indentation of the current line according to Fsharp rules.
  425
+With \\[universal-argument] (programmatically, the optional argument
  426
+ARG non-nil), ignore dedenting rules for block closing statements
  427
+(e.g. return, raise, break, continue, pass)
  428
+
  429
+This function is normally bound to `indent-line-function' so
  430
+\\[indent-for-tab-command] will call it."
  431
+  (interactive "P")
  432
+  (let* ((ci (current-indentation))
  433
+	 (move-to-indentation-p (<= (current-column) ci))
  434
+	 (need (fsharp-compute-indentation (not arg)))
  435
+         (cc (current-column)))
  436
+    ;; dedent out a level if previous command was the same unless we're in
  437
+    ;; column 1
  438
+    (if (and (equal last-command this-command)
  439
+             (/= cc 0))
  440
+        (progn
  441
+          (beginning-of-line)
  442
+          (delete-horizontal-space)
  443
+          (indent-to (* (/ (- cc 1) fsharp-indent-offset) fsharp-indent-offset)))
  444
+      (progn
  445
+	;; see if we need to dedent
  446
+	(if (fsharp-outdent-p)
  447
+	    (setq need (- need fsharp-indent-offset)))
  448
+	(if (or fsharp-tab-always-indent
  449
+		move-to-indentation-p)
  450
+	    (progn (if (/= ci need)
  451
+		       (save-excursion
  452
+		       (beginning-of-line)
  453
+		       (delete-horizontal-space)
  454
+		       (indent-to need)))
  455
+		   (if move-to-indentation-p (back-to-indentation)))
  456
+	    (insert-tab))))))
  457
+
  458
+(defun fsharp-newline-and-indent ()
  459
+  "Strives to act like the Emacs `newline-and-indent'.
  460
+This is just `strives to' because correct indentation can't be computed
  461
+from scratch for Fsharp code.  In general, deletes the whitespace before
  462
+point, inserts a newline, and takes an educated guess as to how you want
  463
+the new line indented."
  464
+  (interactive)
  465
+  (let ((ci (current-indentation)))
  466
+    (if (< ci (current-column))		; if point beyond indentation
  467
+	(newline-and-indent)
  468
+      ;; else try to act like newline-and-indent "normally" acts
  469
+      (beginning-of-line)
  470
+      (insert-char ?\n 1)
  471
+      (move-to-column ci))))
  472
+
  473
+(defun fsharp-compute-indentation (honor-block-close-p)
  474
+  "Compute Fsharp indentation.
  475
+When HONOR-BLOCK-CLOSE-P is non-nil, statements such as `return',
  476
+`raise', `break', `continue', and `pass' force one level of
  477
+dedenting."
  478
+  (save-excursion
  479
+    (beginning-of-line)
  480
+    (let* ((bod (fsharp-point 'bod))
  481
+	   (pps (parse-partial-sexp bod (point)))
  482
+	   (boipps (parse-partial-sexp bod (fsharp-point 'boi)))
  483
+	   placeholder)
  484
+      (cond
  485
+       ;; are we on a continuation line?
  486
+       ((fsharp-continuation-line-p)
  487
+	(let ((startpos (point))
  488
+	      (open-bracket-pos (fsharp-nesting-level))
  489
+	      endpos searching found state)
  490
+	  (if open-bracket-pos
  491
+	      (progn
  492
+		;; align with first item in list; else a normal
  493
+		;; indent beyond the line with the open bracket
  494
+		(goto-char (1+ open-bracket-pos)) ; just beyond bracket
  495
+		;; is the first list item on the same line?
  496
+		(skip-chars-forward " \t")
  497
+		(if (null (memq (following-char) '(?\n ?# ?\\)))
  498
+					; yes, so line up with it
  499
+		    (current-column)
  500
+		  ;; first list item on another line, or doesn't exist yet
  501
+		  (forward-line 1)
  502
+		  (while (and (< (point) startpos)
  503
+			      (looking-at "[ \t]*\\(//\\|[\n\\\\]\\)")) ; skip noise
  504
+		    (forward-line 1))
  505
+		  (if (and (< (point) startpos)
  506
+			   (/= startpos
  507
+			       (save-excursion
  508
+				 (goto-char (1+ open-bracket-pos))
  509
+				 (forward-comment (point-max))
  510
+				 (point))))
  511
+		      ;; again mimic the first list item
  512
+		      (current-indentation)
  513
+		    ;; else they're about to enter the first item
  514
+		    (goto-char open-bracket-pos)
  515
+		    (setq placeholder (point))
  516
+		    (fsharp-goto-initial-line)
  517
+		    (fsharp-goto-beginning-of-tqs
  518
+		     (save-excursion (nth 3 (parse-partial-sexp
  519
+					     placeholder (point)))))
  520
+		    (+ (current-indentation) fsharp-indent-offset))))
  521
+
  522
+	    ;; else on backslash continuation line
  523
+	    (forward-line -1)
  524
+	    (if (fsharp-continuation-line-p) ; on at least 3rd line in block
  525
+		(current-indentation)	; so just continue the pattern
  526
+	      ;; else started on 2nd line in block, so indent more.
  527
+	      ;; if base line is an assignment with a start on a RHS,
  528
+	      ;; indent to 2 beyond the leftmost "="; else skip first
  529
+	      ;; chunk of non-whitespace characters on base line, + 1 more
  530
+	      ;; column
  531
+	      (end-of-line)
  532
+	      (setq endpos (point)
  533
+		    searching t)
  534
+	      (back-to-indentation)
  535
+	      (setq startpos (point))
  536
+	      ;; look at all "=" from left to right, stopping at first
  537
+	      ;; one not nested in a list or string
  538
+	      (while searching
  539
+		(skip-chars-forward "^=" endpos)
  540
+		(if (= (point) endpos)
  541
+		    (setq searching nil)
  542
+		  (forward-char 1)
  543
+		  (setq state (parse-partial-sexp startpos (point)))
  544
+		  (if (and (zerop (car state)) ; not in a bracket
  545
+			   (null (nth 3 state))) ; & not in a string
  546
+		      (progn
  547
+			(setq searching nil) ; done searching in any case
  548
+			(setq found
  549
+			      (not (or
  550
+				    (eq (following-char) ?=)
  551
+				    (memq (char-after (- (point) 2))
  552
+					  '(?< ?> ?!)))))))))
  553
+	      (if (or (not found)	; not an assignment
  554
+		      (looking-at "[ \t]*\\\\")) ; <=><spaces><backslash>
  555
+		  (progn
  556
+		    (goto-char startpos)
  557
+		    (skip-chars-forward "^ \t\n")))
  558
+	      ;; if this is a continuation for a block opening
  559
+	      ;; statement, add some extra offset.
  560
+	      (+ (current-column) (if (fsharp-statement-opens-block-p)
  561
+				      fsharp-continuation-offset 0)
  562
+		 1)
  563
+	      ))))
  564
+
  565
+       ;; not on a continuation line
  566
+       ((bobp) (current-indentation))
  567
+
  568
+       ;; Dfn: "Indenting comment line".  A line containing only a
  569
+       ;; comment, but which is treated like a statement for
  570
+       ;; indentation calculation purposes.  Such lines are only
  571
+       ;; treated specially by the mode; they are not treated
  572
+       ;; specially by the Fsharp interpreter.
  573
+
  574
+       ;; The first non-blank line following an indenting comment
  575
+       ;; line is given the same amount of indentation as the
  576
+       ;; indenting comment line.
  577
+
  578
+       ;; All other comment-only lines are ignored for indentation
  579
+       ;; purposes.
  580
+
  581
+       ;; Are we looking at a comment-only line which is *not* an
  582
+       ;; indenting comment line?  If so, we assume that it's been
  583
+       ;; placed at the desired indentation, so leave it alone.
  584
+       ;; Indenting comment lines are aligned as statements down
  585
+       ;; below.
  586
+       ((and (looking-at "[ \t]*//[^ \t\n]")
  587
+	     ;; NOTE: this test will not be performed in older Emacsen
  588
+	     (fboundp 'forward-comment)
  589
+	     (<= (current-indentation)
  590
+		 (save-excursion
  591
+		   (forward-comment (- (point-max)))
  592
+		   (current-indentation))))
  593
+	(current-indentation))
  594
+
  595
+       ;; else indentation based on that of the statement that
  596
+       ;; precedes us; use the first line of that statement to
  597
+       ;; establish the base, in case the user forced a non-std
  598
+       ;; indentation for the continuation lines (if any)
  599
+       (t
  600
+	;; skip back over blank & non-indenting comment lines note:
  601
+	;; will skip a blank or non-indenting comment line that
  602
+	;; happens to be a continuation line too.  use fast Emacs 19
  603
+	;; function if it's there.
  604
+	(if (and (eq fsharp-honor-comment-indentation nil)
  605
+		 (fboundp 'forward-comment))
  606
+	    (forward-comment (- (point-max)))
  607
+	  (let ((prefix-re "//[ \t]*")
  608
+		done)
  609
+	    (while (not done)
  610
+	      (re-search-backward "^[ \t]*\\([^ \t\n]\\|//\\)" nil 'move)
  611
+	      (setq done (or (bobp)
  612
+			     (and (eq fsharp-honor-comment-indentation t)
  613
+				  (save-excursion
  614
+				    (back-to-indentation)
  615
+				    (not (looking-at prefix-re))
  616
+				    ))
  617
+			     (and (not (eq fsharp-honor-comment-indentation t))
  618
+				  (save-excursion
  619
+				    (back-to-indentation)
  620
+				    (and (not (looking-at prefix-re))
  621
+					 (or (looking-at "[^/]")
  622
+					     (not (zerop (current-column)))
  623
+					     ))
  624
+				    ))
  625
+			     ))
  626
+	      )))
  627
+	;; if we landed inside a string, go to the beginning of that
  628
+	;; string. this handles triple quoted, multi-line spanning
  629
+	;; strings.
  630
+	(fsharp-goto-beginning-of-tqs (nth 3 (parse-partial-sexp bod (point))))
  631
+	;; now skip backward over continued lines
  632
+	(setq placeholder (point))
  633
+	(fsharp-goto-initial-line)
  634
+	;; we may *now* have landed in a TQS, so find the beginning of
  635
+	;; this string.
  636
+	(fsharp-goto-beginning-of-tqs
  637
+	 (save-excursion (nth 3 (parse-partial-sexp
  638
+				 placeholder (point)))))
  639
+	(+ (current-indentation)
  640
+	   (if (fsharp-statement-opens-block-p)
  641
+	       fsharp-indent-offset
  642
+	     (if (and honor-block-close-p (fsharp-statement-closes-block-p))
  643
+		 (- fsharp-indent-offset)
  644
+	       0)))
  645
+	)))))
  646
+
  647
+(defun fsharp-guess-indent-offset (&optional global)
  648
+  "Guess a good value for, and change, `fsharp-indent-offset'.
  649
+
  650
+By default, make a buffer-local copy of `fsharp-indent-offset' with the
  651
+new value, so that other Fsharp buffers are not affected.  With
  652
+\\[universal-argument] (programmatically, optional argument GLOBAL),
  653
+change the global value of `fsharp-indent-offset'.  This affects all
  654
+Fsharp buffers (that don't have their own buffer-local copy), both
  655
+those currently existing and those created later in the Emacs session.
  656
+
  657
+Some people use a different value for `fsharp-indent-offset' than you use.
  658
+There's no excuse for such foolishness, but sometimes you have to deal
  659
+with their ugly code anyway.  This function examines the file and sets
  660
+`fsharp-indent-offset' to what it thinks it was when they created the
  661
+mess.
  662
+
  663
+Specifically, it searches forward from the statement containing point,
  664
+looking for a line that opens a block of code.  `fsharp-indent-offset' is
  665
+set to the difference in indentation between that line and the Fsharp
  666
+statement following it.  If the search doesn't succeed going forward,
  667
+it's tried again going backward."
  668
+  (interactive "P")			; raw prefix arg
  669
+  (let (new-value
  670
+	(start (point))
  671
+	(restart (point))
  672
+	(found nil)
  673
+	colon-indent)
  674
+    (fsharp-goto-initial-line)
  675
+    (while (not (or found (eobp)))
  676
+      (when (and (re-search-forward fsharp-block-opening-re nil 'move)
  677
+		 (not (fsharp-in-literal restart)))
  678
+	(setq restart (point))
  679
+	(fsharp-goto-initial-line)
  680
+	(if (fsharp-statement-opens-block-p)
  681
+	    (setq found t)
  682
+	  (goto-char restart))))
  683
+    (unless found
  684
+      (goto-char start)
  685
+      (fsharp-goto-initial-line)
  686
+      (while (not (or found (bobp)))
  687
+	(setq found (and
  688
+		     (re-search-backward fsharp-block-opening-re nil 'move)
  689
+		     (or (fsharp-goto-initial-line) t) ; always true -- side effect
  690
+		     (fsharp-statement-opens-block-p)))))
  691
+    (setq colon-indent (current-indentation)
  692
+	  found (and found (zerop (fsharp-next-statement 1)))
  693
+	  new-value (- (current-indentation) colon-indent))
  694
+    (goto-char start)
  695
+    (if (not found)
  696
+	(error "Sorry, couldn't guess a value for fsharp-indent-offset")
  697
+      (funcall (if global 'kill-local-variable 'make-local-variable)
  698
+	       'fsharp-indent-offset)
  699
+      (setq fsharp-indent-offset new-value)
  700
+      (or noninteractive
  701
+	  (message "%s value of fsharp-indent-offset set to %d"
  702
+		   (if global "Global" "Local")
  703
+		   fsharp-indent-offset)))
  704
+    ))
  705
+
  706
+(defun fsharp-comment-indent-function ()
  707
+  "Fsharp version of `comment-indent-function'."
  708
+  ;; This is required when filladapt is turned off.  Without it, when
  709
+  ;; filladapt is not used, comments which start in column zero
  710
+  ;; cascade one character to the right
  711
+  (save-excursion
  712
+    (beginning-of-line)
  713
+    (let ((eol (fsharp-point 'eol)))
  714
+      (and comment-start-skip
  715
+	   (re-search-forward comment-start-skip eol t)
  716
+	   (setq eol (match-beginning 0)))
  717
+      (goto-char eol)
  718
+      (skip-chars-backward " \t")
  719
+      (max comment-column (+ (current-column) (if (bolp) 0 1)))
  720
+      )))
  721
+
  722
+(defun fsharp-narrow-to-defun (&optional class)
  723
+  "Make text outside current defun invisible.
  724
+The defun visible is the one that contains point or follows point.
  725
+Optional CLASS is passed directly to `fsharp-beginning-of-def-or-class'."
  726
+  (interactive "P")
  727
+  (save-excursion
  728
+    (widen)
  729
+    (fsharp-end-of-def-or-class class)
  730
+    (let ((end (point)))
  731
+      (fsharp-beginning-of-def-or-class class)
  732
+      (narrow-to-region (point) end))))
  733
+
  734
+
  735
+(defun fsharp-shift-region (start end count)
  736
+  "Indent lines from START to END by COUNT spaces."
  737
+  (save-excursion
  738
+    (goto-char end)
  739
+    (beginning-of-line)
  740
+    (setq end (point))
  741
+    (goto-char start)
  742
+    (beginning-of-line)
  743
+    (setq start (point))
  744
+    (indent-rigidly start end count)))
  745
+
  746
+(defun fsharp-shift-region-left (start end &optional count)
  747
+  "Shift region of Fsharp code to the left.
  748
+The lines from the line containing the start of the current region up
  749
+to (but not including) the line containing the end of the region are
  750
+shifted to the left, by `fsharp-indent-offset' columns.
  751
+
  752
+If a prefix argument is given, the region is instead shifted by that
  753
+many columns.  With no active region, dedent only the current line.
  754
+You cannot dedent the region if any line is already at column zero."
  755
+  (interactive
  756
+   (let ((p (point))
  757
+	 (m (mark))
  758
+	 (arg current-prefix-arg))
  759
+     (if m
  760
+	 (list (min p m) (max p m) arg)
  761
+       (list p (save-excursion (forward-line 1) (point)) arg))))
  762
+  ;; if any line is at column zero, don't shift the region
  763
+  (save-excursion
  764
+    (goto-char start)
  765
+    (while (< (point) end)
  766
+      (back-to-indentation)
  767
+      (if (and (zerop (current-column))
  768
+	       (not (looking-at "\\s *$")))
  769
+	  (error "Region is at left edge"))
  770
+      (forward-line 1)))
  771
+  (fsharp-shift-region start end (- (prefix-numeric-value
  772
+				 (or count fsharp-indent-offset))))
  773
+  (fsharp-keep-region-active))
  774
+
  775
+(defun fsharp-shift-region-right (start end &optional count)
  776
+  "Shift region of Fsharp code to the right.
  777
+The lines from the line containing the start of the current region up
  778
+to (but not including) the line containing the end of the region are
  779
+shifted to the right, by `fsharp-indent-offset' columns.
  780
+
  781
+If a prefix argument is given, the region is instead shifted by that
  782
+many columns.  With no active region, indent only the current line."
  783
+  (interactive
  784
+   (let ((p (point))
  785
+	 (m (mark))
  786
+	 (arg current-prefix-arg))
  787
+     (if m
  788
+	 (list (min p m) (max p m) arg)
  789
+       (list p (save-excursion (forward-line 1) (point)) arg))))
  790
+  (fsharp-shift-region start end (prefix-numeric-value
  791
+			      (or count fsharp-indent-offset)))
  792
+  (fsharp-keep-region-active))
  793
+
  794
+(defun fsharp-indent-region (start end &optional indent-offset)
  795
+  "Reindent a region of Fsharp code.
  796
+
  797
+The lines from the line containing the start of the current region up
  798
+to (but not including) the line containing the end of the region are
  799
+reindented.  If the first line of the region has a non-whitespace
  800
+character in the first column, the first line is left alone and the
  801
+rest of the region is reindented with respect to it.  Else the entire
  802
+region is reindented with respect to the (closest code or indenting
  803
+comment) statement immediately preceding the region.
  804
+
  805
+This is useful when code blocks are moved or yanked, when enclosing
  806
+control structures are introduced or removed, or to reformat code
  807
+using a new value for the indentation offset.
  808
+
  809
+If a numeric prefix argument is given, it will be used as the value of
  810
+the indentation offset.  Else the value of `fsharp-indent-offset' will be
  811
+used.
  812
+
  813
+Warning: The region must be consistently indented before this function
  814
+is called!  This function does not compute proper indentation from
  815
+scratch (that's impossible in Fsharp), it merely adjusts the existing
  816
+indentation to be correct in context.
  817
+
  818
+Warning: This function really has no idea what to do with
  819
+non-indenting comment lines, and shifts them as if they were indenting
  820
+comment lines.  Fixing this appears to require telepathy.
  821
+
  822
+Special cases: whitespace is deleted from blank lines; continuation
  823
+lines are shifted by the same amount their initial line was shifted,
  824
+in order to preserve their relative indentation with respect to their
  825
+initial line; and comment lines beginning in column 1 are ignored."
  826
+  (interactive "*r\nP")			; region; raw prefix arg
  827
+  (save-excursion
  828
+    (goto-char end)   (beginning-of-line) (setq end (point-marker))
  829
+    (goto-char start) (beginning-of-line)
  830
+    (let ((fsharp-indent-offset (prefix-numeric-value
  831
+			     (or indent-offset fsharp-indent-offset)))
  832
+	  (indents '(-1))		; stack of active indent levels
  833
+	  (target-column 0)		; column to which to indent
  834
+	  (base-shifted-by 0)		; amount last base line was shifted
  835
+	  (indent-base (if (looking-at "[ \t\n]")
  836
+			   (fsharp-compute-indentation t)
  837
+			 0))
  838
+	  ci)
  839
+      (while (< (point) end)
  840
+	(setq ci (current-indentation))
  841
+	;; figure out appropriate target column
  842
+	(cond
  843
+	 ((or (looking-at "//")	; comment in column 1
  844
+	      (looking-at "[ \t]*$"))	; entirely blank
  845
+	  (setq target-column 0))
  846
+	 ((fsharp-continuation-line-p)	; shift relative to base line
  847
+	  (setq target-column (+ ci base-shifted-by)))
  848
+	 (t				; new base line
  849
+	  (if (> ci (car indents))	; going deeper; push it
  850
+	      (setq indents (cons ci indents))
  851
+	    ;; else we should have seen this indent before
  852
+	    (setq indents (memq ci indents)) ; pop deeper indents
  853
+	    (if (null indents)
  854
+		(error "Bad indentation in region, at line %d"
  855
+		       (save-restriction
  856
+			 (widen)
  857
+			 (1+ (count-lines 1 (point)))))))
  858
+	  (setq target-column (+ indent-base
  859
+				 (* fsharp-indent-offset
  860
+				    (- (length indents) 2))))
  861
+	  (setq base-shifted-by (- target-column ci))))
  862
+	;; shift as needed
  863
+	(if (/= ci target-column)
  864
+	    (progn
  865
+	      (delete-horizontal-space)
  866
+	      (indent-to target-column)))
  867
+	(forward-line 1))))
  868
+  (set-marker end nil))
  869
+
  870
+
  871
+;; Functions for moving point
  872
+(defun fsharp-previous-statement (count)
  873
+  "Go to the start of the COUNTth preceding Fsharp statement.
  874
+By default, goes to the previous statement.  If there is no such
  875
+statement, goes to the first statement.  Return count of statements
  876
+left to move.  `Statements' do not include blank, comment, or
  877
+continuation lines."
  878
+  (interactive "p")			; numeric prefix arg
  879
+  (if (< count 0) (fsharp-next-statement (- count))
  880
+    (fsharp-goto-initial-line)
  881
+    (let (start)
  882
+      (while (and
  883
+	      (setq start (point))	; always true -- side effect
  884
+	      (> count 0)
  885
+	      (zerop (forward-line -1))
  886
+	      (fsharp-goto-statement-at-or-above))
  887
+	(setq count (1- count)))
  888
+      (if (> count 0) (goto-char start)))
  889
+    count))
  890
+
  891
+(defun fsharp-next-statement (count)
  892
+  "Go to the start of next Fsharp statement.
  893
+If the statement at point is the i'th Fsharp statement, goes to the
  894
+start of statement i+COUNT.  If there is no such statement, goes to the
  895
+last statement.  Returns count of statements left to move.  `Statements'
  896
+do not include blank, comment, or continuation lines."
  897
+  (interactive "p")			; numeric prefix arg
  898
+  (if (< count 0) (fsharp-previous-statement (- count))
  899
+    (beginning-of-line)
  900
+    (let (start)
  901
+      (while (and
  902
+	      (setq start (point))	; always true -- side effect
  903
+	      (> count 0)
  904
+	      (fsharp-goto-statement-below))
  905
+	(setq count (1- count)))
  906
+      (if (> count 0) (goto-char start)))
  907
+    count))
  908
+
  909
+(defun fsharp-goto-block-up (&optional nomark)
  910
+  "Move up to start of current block.
  911
+Go to the statement that starts the smallest enclosing block; roughly
  912
+speaking, this will be the closest preceding statement that ends with a
  913
+colon and is indented less than the statement you started on.  If
  914
+successful, also sets the mark to the starting point.
  915
+
  916
+`\\[fsharp-mark-block]' can be used afterward to mark the whole code
  917
+block, if desired.
  918
+
  919
+If called from a program, the mark will not be set if optional argument
  920
+NOMARK is not nil."
  921
+  (interactive)
  922
+  (let ((start (point))
  923
+	(found nil)
  924
+	initial-indent)
  925
+    (fsharp-goto-initial-line)
  926
+    ;; if on blank or non-indenting comment line, use the preceding stmt
  927
+    (if (looking-at "[ \t]*\\($\\|//[^ \t\n]\\)")
  928
+	(progn
  929
+	  (fsharp-goto-statement-at-or-above)
  930
+	  (setq found (fsharp-statement-opens-block-p))))
  931
+    ;; search back for colon line indented less
  932
+    (setq initial-indent (current-indentation))
  933
+    (if (zerop initial-indent)
  934
+	;; force fast exit
  935
+	(goto-char (point-min)))
  936
+    (while (not (or found (bobp)))
  937
+      (setq found
  938
+	    (and
  939
+	     (re-search-backward fsharp-block-opening-re nil 'move)
  940
+	     (or (fsharp-goto-initial-line) t) ; always true -- side effect
  941
+	     (< (current-indentation) initial-indent)
  942
+	     (fsharp-statement-opens-block-p))))
  943
+    (if found
  944
+	(progn
  945
+	  (or nomark (push-mark start))
  946
+	  (back-to-indentation))
  947
+      (goto-char start)
  948
+      (error "Enclosing block not found"))))
  949
+
  950
+;;FIXME
  951
+(defun fsharp-beginning-of-def-or-class (&optional class count)
  952
+  "Move point to start of `def' or `class'.
  953
+
  954
+Searches back for the closest preceding `def'.  If you supply a prefix
  955
+arg, looks for a `class' instead.  The docs below assume the `def'
  956
+case; just substitute `class' for `def' for the other case.
  957
+Programmatically, if CLASS is `either', then moves to either `class'
  958
+or `def'.
  959
+
  960
+When second optional argument is given programmatically, move to the
  961
+COUNTth start of `def'.
  962
+
  963
+If point is in a `def' statement already, and after the `d', simply
  964
+moves point to the start of the statement.
  965
+
  966
+Otherwise (i.e. when point is not in a `def' statement, or at or
  967
+before the `d' of a `def' statement), searches for the closest